e67143243a
bfad.c & bfad_drv.h: * Created a kernel thread from pci_probe that does the bfad start operations after BFA init done on a firmware mismatch. * The kernel thread on a fw mismatch waits for an event from IOC call back and is woken up from bfa_cb_init() on BFA init success. * In normal cases of no firmware mismatch this thread is terminated in pci_probe. bfa_fcs_lport.c, fabric.c, fcs_lport.h & vport.c: * Split the lport init to attach time and init time code, so that proper config attributes are set after firmware mismatch. bfa_iocfc.c: * Handle an IOC timer issue, where the IOC timer would expire before the init completion and send Init fail event to the driver, however IOC init continues and completes successfully at the later stage. The bfa and driver were not handling this kind of deferred init completion. Signed-off-by: Krishna Gudipati <kgudipat@brocade.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
876 lines
21 KiB
C
876 lines
21 KiB
C
/*
|
|
* Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
|
|
* All rights reserved
|
|
* www.brocade.com
|
|
*
|
|
* Linux driver for Brocade Fibre Channel Host Bus Adapter.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License (GPL) Version 2 as
|
|
* published by the Free Software Foundation
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*/
|
|
|
|
#include <cs/bfa_debug.h>
|
|
#include <bfa_priv.h>
|
|
#include <log/bfa_log_hal.h>
|
|
#include <bfi/bfi_boot.h>
|
|
#include <bfi/bfi_cbreg.h>
|
|
#include <aen/bfa_aen_ioc.h>
|
|
#include <defs/bfa_defs_iocfc.h>
|
|
#include <defs/bfa_defs_pci.h>
|
|
#include "bfa_callback_priv.h"
|
|
#include "bfad_drv.h"
|
|
|
|
BFA_TRC_FILE(HAL, IOCFC);
|
|
|
|
/**
|
|
* IOC local definitions
|
|
*/
|
|
#define BFA_IOCFC_TOV 5000 /* msecs */
|
|
|
|
enum {
|
|
BFA_IOCFC_ACT_NONE = 0,
|
|
BFA_IOCFC_ACT_INIT = 1,
|
|
BFA_IOCFC_ACT_STOP = 2,
|
|
BFA_IOCFC_ACT_DISABLE = 3,
|
|
};
|
|
|
|
/*
|
|
* forward declarations
|
|
*/
|
|
static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status);
|
|
static void bfa_iocfc_disable_cbfn(void *bfa_arg);
|
|
static void bfa_iocfc_hbfail_cbfn(void *bfa_arg);
|
|
static void bfa_iocfc_reset_cbfn(void *bfa_arg);
|
|
static void bfa_iocfc_stats_clear(void *bfa_arg);
|
|
static void bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d,
|
|
struct bfa_fw_stats_s *s);
|
|
static void bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete);
|
|
static void bfa_iocfc_stats_clr_timeout(void *bfa_arg);
|
|
static void bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete);
|
|
static void bfa_iocfc_stats_timeout(void *bfa_arg);
|
|
|
|
static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn;
|
|
|
|
/**
|
|
* bfa_ioc_pvt BFA IOC private functions
|
|
*/
|
|
|
|
static void
|
|
bfa_iocfc_cqs_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len)
|
|
{
|
|
int i, per_reqq_sz, per_rspq_sz;
|
|
|
|
per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ),
|
|
BFA_DMA_ALIGN_SZ);
|
|
per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ),
|
|
BFA_DMA_ALIGN_SZ);
|
|
|
|
/*
|
|
* Calculate CQ size
|
|
*/
|
|
for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
|
|
*dm_len = *dm_len + per_reqq_sz;
|
|
*dm_len = *dm_len + per_rspq_sz;
|
|
}
|
|
|
|
/*
|
|
* Calculate Shadow CI/PI size
|
|
*/
|
|
for (i = 0; i < cfg->fwcfg.num_cqs; i++)
|
|
*dm_len += (2 * BFA_CACHELINE_SZ);
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len)
|
|
{
|
|
*dm_len +=
|
|
BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
|
|
*dm_len +=
|
|
BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
|
|
BFA_CACHELINE_SZ);
|
|
*dm_len += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
|
|
}
|
|
|
|
/**
|
|
* Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ
|
|
*/
|
|
static void
|
|
bfa_iocfc_send_cfg(void *bfa_arg)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
struct bfi_iocfc_cfg_req_s cfg_req;
|
|
struct bfi_iocfc_cfg_s *cfg_info = iocfc->cfginfo;
|
|
struct bfa_iocfc_cfg_s *cfg = &iocfc->cfg;
|
|
int i;
|
|
|
|
bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS);
|
|
bfa_trc(bfa, cfg->fwcfg.num_cqs);
|
|
|
|
iocfc->cfgdone = BFA_FALSE;
|
|
bfa_iocfc_reset_queues(bfa);
|
|
|
|
/**
|
|
* initialize IOC configuration info
|
|
*/
|
|
cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG;
|
|
cfg_info->num_cqs = cfg->fwcfg.num_cqs;
|
|
|
|
bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa);
|
|
bfa_dma_be_addr_set(cfg_info->stats_addr, iocfc->stats_pa);
|
|
|
|
/**
|
|
* dma map REQ and RSP circular queues and shadow pointers
|
|
*/
|
|
for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
|
|
bfa_dma_be_addr_set(cfg_info->req_cq_ba[i],
|
|
iocfc->req_cq_ba[i].pa);
|
|
bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i],
|
|
iocfc->req_cq_shadow_ci[i].pa);
|
|
cfg_info->req_cq_elems[i] =
|
|
bfa_os_htons(cfg->drvcfg.num_reqq_elems);
|
|
|
|
bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i],
|
|
iocfc->rsp_cq_ba[i].pa);
|
|
bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i],
|
|
iocfc->rsp_cq_shadow_pi[i].pa);
|
|
cfg_info->rsp_cq_elems[i] =
|
|
bfa_os_htons(cfg->drvcfg.num_rspq_elems);
|
|
}
|
|
|
|
/**
|
|
* dma map IOC configuration itself
|
|
*/
|
|
bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ,
|
|
bfa_lpuid(bfa));
|
|
bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa);
|
|
|
|
bfa_ioc_mbox_send(&bfa->ioc, &cfg_req,
|
|
sizeof(struct bfi_iocfc_cfg_req_s));
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
|
|
struct bfa_pcidev_s *pcidev)
|
|
{
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
|
|
bfa->bfad = bfad;
|
|
iocfc->bfa = bfa;
|
|
iocfc->action = BFA_IOCFC_ACT_NONE;
|
|
|
|
bfa_os_assign(iocfc->cfg, *cfg);
|
|
|
|
/**
|
|
* Initialize chip specific handlers.
|
|
*/
|
|
if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) {
|
|
iocfc->hwif.hw_reginit = bfa_hwct_reginit;
|
|
iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack;
|
|
iocfc->hwif.hw_msix_init = bfa_hwct_msix_init;
|
|
iocfc->hwif.hw_msix_install = bfa_hwct_msix_install;
|
|
iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall;
|
|
iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set;
|
|
iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs;
|
|
} else {
|
|
iocfc->hwif.hw_reginit = bfa_hwcb_reginit;
|
|
iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack;
|
|
iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init;
|
|
iocfc->hwif.hw_msix_install = bfa_hwcb_msix_install;
|
|
iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall;
|
|
iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set;
|
|
iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs;
|
|
}
|
|
|
|
iocfc->hwif.hw_reginit(bfa);
|
|
bfa->msix.nvecs = 0;
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg,
|
|
struct bfa_meminfo_s *meminfo)
|
|
{
|
|
u8 *dm_kva;
|
|
u64 dm_pa;
|
|
int i, per_reqq_sz, per_rspq_sz;
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
int dbgsz;
|
|
|
|
dm_kva = bfa_meminfo_dma_virt(meminfo);
|
|
dm_pa = bfa_meminfo_dma_phys(meminfo);
|
|
|
|
/*
|
|
* First allocate dma memory for IOC.
|
|
*/
|
|
bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa);
|
|
dm_kva += bfa_ioc_meminfo();
|
|
dm_pa += bfa_ioc_meminfo();
|
|
|
|
/*
|
|
* Claim DMA-able memory for the request/response queues and for shadow
|
|
* ci/pi registers
|
|
*/
|
|
per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ),
|
|
BFA_DMA_ALIGN_SZ);
|
|
per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ),
|
|
BFA_DMA_ALIGN_SZ);
|
|
|
|
for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
|
|
iocfc->req_cq_ba[i].kva = dm_kva;
|
|
iocfc->req_cq_ba[i].pa = dm_pa;
|
|
bfa_os_memset(dm_kva, 0, per_reqq_sz);
|
|
dm_kva += per_reqq_sz;
|
|
dm_pa += per_reqq_sz;
|
|
|
|
iocfc->rsp_cq_ba[i].kva = dm_kva;
|
|
iocfc->rsp_cq_ba[i].pa = dm_pa;
|
|
bfa_os_memset(dm_kva, 0, per_rspq_sz);
|
|
dm_kva += per_rspq_sz;
|
|
dm_pa += per_rspq_sz;
|
|
}
|
|
|
|
for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
|
|
iocfc->req_cq_shadow_ci[i].kva = dm_kva;
|
|
iocfc->req_cq_shadow_ci[i].pa = dm_pa;
|
|
dm_kva += BFA_CACHELINE_SZ;
|
|
dm_pa += BFA_CACHELINE_SZ;
|
|
|
|
iocfc->rsp_cq_shadow_pi[i].kva = dm_kva;
|
|
iocfc->rsp_cq_shadow_pi[i].pa = dm_pa;
|
|
dm_kva += BFA_CACHELINE_SZ;
|
|
dm_pa += BFA_CACHELINE_SZ;
|
|
}
|
|
|
|
/*
|
|
* Claim DMA-able memory for the config info page
|
|
*/
|
|
bfa->iocfc.cfg_info.kva = dm_kva;
|
|
bfa->iocfc.cfg_info.pa = dm_pa;
|
|
bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva;
|
|
dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
|
|
dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
|
|
|
|
/*
|
|
* Claim DMA-able memory for the config response
|
|
*/
|
|
bfa->iocfc.cfgrsp_dma.kva = dm_kva;
|
|
bfa->iocfc.cfgrsp_dma.pa = dm_pa;
|
|
bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva;
|
|
|
|
dm_kva +=
|
|
BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
|
|
BFA_CACHELINE_SZ);
|
|
dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
|
|
BFA_CACHELINE_SZ);
|
|
|
|
/*
|
|
* Claim DMA-able memory for iocfc stats
|
|
*/
|
|
bfa->iocfc.stats_kva = dm_kva;
|
|
bfa->iocfc.stats_pa = dm_pa;
|
|
bfa->iocfc.fw_stats = (struct bfa_fw_stats_s *) dm_kva;
|
|
dm_kva += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
|
|
dm_pa += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
|
|
|
|
bfa_meminfo_dma_virt(meminfo) = dm_kva;
|
|
bfa_meminfo_dma_phys(meminfo) = dm_pa;
|
|
|
|
dbgsz = bfa_ioc_debug_trcsz(bfa_auto_recover);
|
|
if (dbgsz > 0) {
|
|
bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo));
|
|
bfa_meminfo_kva(meminfo) += dbgsz;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* BFA submodules initialization completion notification.
|
|
*/
|
|
static void
|
|
bfa_iocfc_initdone_submod(struct bfa_s *bfa)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; hal_mods[i]; i++)
|
|
hal_mods[i]->initdone(bfa);
|
|
}
|
|
|
|
/**
|
|
* Start BFA submodules.
|
|
*/
|
|
static void
|
|
bfa_iocfc_start_submod(struct bfa_s *bfa)
|
|
{
|
|
int i;
|
|
|
|
bfa->rme_process = BFA_TRUE;
|
|
|
|
for (i = 0; hal_mods[i]; i++)
|
|
hal_mods[i]->start(bfa);
|
|
}
|
|
|
|
/**
|
|
* Disable BFA submodules.
|
|
*/
|
|
static void
|
|
bfa_iocfc_disable_submod(struct bfa_s *bfa)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; hal_mods[i]; i++)
|
|
hal_mods[i]->iocdisable(bfa);
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
|
|
if (complete) {
|
|
if (bfa->iocfc.cfgdone)
|
|
bfa_cb_init(bfa->bfad, BFA_STATUS_OK);
|
|
else
|
|
bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED);
|
|
} else {
|
|
if (bfa->iocfc.cfgdone)
|
|
bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
struct bfad_s *bfad = bfa->bfad;
|
|
|
|
if (compl)
|
|
complete(&bfad->comp);
|
|
|
|
else
|
|
bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
struct bfad_s *bfad = bfa->bfad;
|
|
|
|
if (compl)
|
|
complete(&bfad->disable_comp);
|
|
}
|
|
|
|
/**
|
|
* Update BFA configuration from firmware configuration.
|
|
*/
|
|
static void
|
|
bfa_iocfc_cfgrsp(struct bfa_s *bfa)
|
|
{
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
|
|
struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg;
|
|
struct bfi_iocfc_cfg_s *cfginfo = iocfc->cfginfo;
|
|
|
|
fwcfg->num_cqs = fwcfg->num_cqs;
|
|
fwcfg->num_ioim_reqs = bfa_os_ntohs(fwcfg->num_ioim_reqs);
|
|
fwcfg->num_tskim_reqs = bfa_os_ntohs(fwcfg->num_tskim_reqs);
|
|
fwcfg->num_fcxp_reqs = bfa_os_ntohs(fwcfg->num_fcxp_reqs);
|
|
fwcfg->num_uf_bufs = bfa_os_ntohs(fwcfg->num_uf_bufs);
|
|
fwcfg->num_rports = bfa_os_ntohs(fwcfg->num_rports);
|
|
|
|
cfginfo->intr_attr.coalesce = cfgrsp->intr_attr.coalesce;
|
|
cfginfo->intr_attr.delay = bfa_os_ntohs(cfgrsp->intr_attr.delay);
|
|
cfginfo->intr_attr.latency = bfa_os_ntohs(cfgrsp->intr_attr.latency);
|
|
|
|
iocfc->cfgdone = BFA_TRUE;
|
|
|
|
/**
|
|
* Configuration is complete - initialize/start submodules
|
|
*/
|
|
if (iocfc->action == BFA_IOCFC_ACT_INIT)
|
|
bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa);
|
|
else
|
|
bfa_iocfc_start_submod(bfa);
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_stats_clear(void *bfa_arg)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
struct bfi_iocfc_stats_req_s stats_req;
|
|
|
|
bfa_timer_start(bfa, &iocfc->stats_timer,
|
|
bfa_iocfc_stats_clr_timeout, bfa,
|
|
BFA_IOCFC_TOV);
|
|
|
|
bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CLEAR_STATS_REQ,
|
|
bfa_lpuid(bfa));
|
|
bfa_ioc_mbox_send(&bfa->ioc, &stats_req,
|
|
sizeof(struct bfi_iocfc_stats_req_s));
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d, struct bfa_fw_stats_s *s)
|
|
{
|
|
u32 *dip = (u32 *) d;
|
|
u32 *sip = (u32 *) s;
|
|
int i;
|
|
|
|
for (i = 0; i < (sizeof(struct bfa_fw_stats_s) / sizeof(u32)); i++)
|
|
dip[i] = bfa_os_ntohl(sip[i]);
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
|
|
if (complete) {
|
|
bfa_ioc_clr_stats(&bfa->ioc);
|
|
iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status);
|
|
} else {
|
|
iocfc->stats_busy = BFA_FALSE;
|
|
iocfc->stats_status = BFA_STATUS_OK;
|
|
}
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_stats_clr_timeout(void *bfa_arg)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
|
|
bfa_trc(bfa, 0);
|
|
|
|
iocfc->stats_status = BFA_STATUS_ETIMER;
|
|
bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_clr_cb, bfa);
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
|
|
if (complete) {
|
|
if (iocfc->stats_status == BFA_STATUS_OK) {
|
|
bfa_os_memset(iocfc->stats_ret, 0,
|
|
sizeof(*iocfc->stats_ret));
|
|
bfa_iocfc_stats_swap(&iocfc->stats_ret->fw_stats,
|
|
iocfc->fw_stats);
|
|
}
|
|
iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status);
|
|
} else {
|
|
iocfc->stats_busy = BFA_FALSE;
|
|
iocfc->stats_status = BFA_STATUS_OK;
|
|
}
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_stats_timeout(void *bfa_arg)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
|
|
bfa_trc(bfa, 0);
|
|
|
|
iocfc->stats_status = BFA_STATUS_ETIMER;
|
|
bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb, bfa);
|
|
}
|
|
|
|
static void
|
|
bfa_iocfc_stats_query(struct bfa_s *bfa)
|
|
{
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
struct bfi_iocfc_stats_req_s stats_req;
|
|
|
|
bfa_timer_start(bfa, &iocfc->stats_timer,
|
|
bfa_iocfc_stats_timeout, bfa, BFA_IOCFC_TOV);
|
|
|
|
bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_GET_STATS_REQ,
|
|
bfa_lpuid(bfa));
|
|
bfa_ioc_mbox_send(&bfa->ioc, &stats_req,
|
|
sizeof(struct bfi_iocfc_stats_req_s));
|
|
}
|
|
|
|
void
|
|
bfa_iocfc_reset_queues(struct bfa_s *bfa)
|
|
{
|
|
int q;
|
|
|
|
for (q = 0; q < BFI_IOC_MAX_CQS; q++) {
|
|
bfa_reqq_ci(bfa, q) = 0;
|
|
bfa_reqq_pi(bfa, q) = 0;
|
|
bfa_rspq_ci(bfa, q) = 0;
|
|
bfa_rspq_pi(bfa, q) = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* IOC enable request is complete
|
|
*/
|
|
static void
|
|
bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
|
|
if (status != BFA_STATUS_OK) {
|
|
bfa_isr_disable(bfa);
|
|
if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT)
|
|
bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe,
|
|
bfa_iocfc_init_cb, bfa);
|
|
return;
|
|
}
|
|
|
|
bfa_iocfc_initdone_submod(bfa);
|
|
bfa_iocfc_send_cfg(bfa);
|
|
}
|
|
|
|
/**
|
|
* IOC disable request is complete
|
|
*/
|
|
static void
|
|
bfa_iocfc_disable_cbfn(void *bfa_arg)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
|
|
bfa_isr_disable(bfa);
|
|
bfa_iocfc_disable_submod(bfa);
|
|
|
|
if (bfa->iocfc.action == BFA_IOCFC_ACT_STOP)
|
|
bfa_cb_queue(bfa, &bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb,
|
|
bfa);
|
|
else {
|
|
bfa_assert(bfa->iocfc.action == BFA_IOCFC_ACT_DISABLE);
|
|
bfa_cb_queue(bfa, &bfa->iocfc.dis_hcb_qe, bfa_iocfc_disable_cb,
|
|
bfa);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Notify sub-modules of hardware failure.
|
|
*/
|
|
static void
|
|
bfa_iocfc_hbfail_cbfn(void *bfa_arg)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
|
|
bfa->rme_process = BFA_FALSE;
|
|
|
|
bfa_isr_disable(bfa);
|
|
bfa_iocfc_disable_submod(bfa);
|
|
|
|
if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT)
|
|
bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb,
|
|
bfa);
|
|
}
|
|
|
|
/**
|
|
* Actions on chip-reset completion.
|
|
*/
|
|
static void
|
|
bfa_iocfc_reset_cbfn(void *bfa_arg)
|
|
{
|
|
struct bfa_s *bfa = bfa_arg;
|
|
|
|
bfa_iocfc_reset_queues(bfa);
|
|
bfa_isr_enable(bfa);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* bfa_ioc_public
|
|
*/
|
|
|
|
/**
|
|
* Query IOC memory requirement information.
|
|
*/
|
|
void
|
|
bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
|
|
u32 *dm_len)
|
|
{
|
|
/* dma memory for IOC */
|
|
*dm_len += bfa_ioc_meminfo();
|
|
|
|
bfa_iocfc_fw_cfg_sz(cfg, dm_len);
|
|
bfa_iocfc_cqs_sz(cfg, dm_len);
|
|
*km_len += bfa_ioc_debug_trcsz(bfa_auto_recover);
|
|
}
|
|
|
|
/**
|
|
* Query IOC memory requirement information.
|
|
*/
|
|
void
|
|
bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
|
|
struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
|
|
{
|
|
int i;
|
|
|
|
bfa_iocfc_cbfn.enable_cbfn = bfa_iocfc_enable_cbfn;
|
|
bfa_iocfc_cbfn.disable_cbfn = bfa_iocfc_disable_cbfn;
|
|
bfa_iocfc_cbfn.hbfail_cbfn = bfa_iocfc_hbfail_cbfn;
|
|
bfa_iocfc_cbfn.reset_cbfn = bfa_iocfc_reset_cbfn;
|
|
|
|
bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod,
|
|
bfa->trcmod, bfa->aen, bfa->logm);
|
|
|
|
/**
|
|
* Choose FC (ssid: 0x1C) v/s FCoE (ssid: 0x14) mode.
|
|
*/
|
|
if (0)
|
|
bfa_ioc_set_fcmode(&bfa->ioc);
|
|
|
|
bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC);
|
|
bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs);
|
|
|
|
bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev);
|
|
bfa_iocfc_mem_claim(bfa, cfg, meminfo);
|
|
bfa_timer_init(&bfa->timer_mod);
|
|
|
|
INIT_LIST_HEAD(&bfa->comp_q);
|
|
for (i = 0; i < BFI_IOC_MAX_CQS; i++)
|
|
INIT_LIST_HEAD(&bfa->reqq_waitq[i]);
|
|
}
|
|
|
|
/**
|
|
* Query IOC memory requirement information.
|
|
*/
|
|
void
|
|
bfa_iocfc_detach(struct bfa_s *bfa)
|
|
{
|
|
bfa_ioc_detach(&bfa->ioc);
|
|
}
|
|
|
|
/**
|
|
* Query IOC memory requirement information.
|
|
*/
|
|
void
|
|
bfa_iocfc_init(struct bfa_s *bfa)
|
|
{
|
|
bfa->iocfc.action = BFA_IOCFC_ACT_INIT;
|
|
bfa_ioc_enable(&bfa->ioc);
|
|
bfa_msix_install(bfa);
|
|
}
|
|
|
|
/**
|
|
* IOC start called from bfa_start(). Called to start IOC operations
|
|
* at driver instantiation for this instance.
|
|
*/
|
|
void
|
|
bfa_iocfc_start(struct bfa_s *bfa)
|
|
{
|
|
if (bfa->iocfc.cfgdone)
|
|
bfa_iocfc_start_submod(bfa);
|
|
}
|
|
|
|
/**
|
|
* IOC stop called from bfa_stop(). Called only when driver is unloaded
|
|
* for this instance.
|
|
*/
|
|
void
|
|
bfa_iocfc_stop(struct bfa_s *bfa)
|
|
{
|
|
bfa->iocfc.action = BFA_IOCFC_ACT_STOP;
|
|
|
|
bfa->rme_process = BFA_FALSE;
|
|
bfa_ioc_disable(&bfa->ioc);
|
|
}
|
|
|
|
void
|
|
bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m)
|
|
{
|
|
struct bfa_s *bfa = bfaarg;
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
union bfi_iocfc_i2h_msg_u *msg;
|
|
|
|
msg = (union bfi_iocfc_i2h_msg_u *) m;
|
|
bfa_trc(bfa, msg->mh.msg_id);
|
|
|
|
switch (msg->mh.msg_id) {
|
|
case BFI_IOCFC_I2H_CFG_REPLY:
|
|
iocfc->cfg_reply = &msg->cfg_reply;
|
|
bfa_iocfc_cfgrsp(bfa);
|
|
break;
|
|
|
|
case BFI_IOCFC_I2H_GET_STATS_RSP:
|
|
if (iocfc->stats_busy == BFA_FALSE
|
|
|| iocfc->stats_status == BFA_STATUS_ETIMER)
|
|
break;
|
|
|
|
bfa_timer_stop(&iocfc->stats_timer);
|
|
iocfc->stats_status = BFA_STATUS_OK;
|
|
bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb,
|
|
bfa);
|
|
break;
|
|
case BFI_IOCFC_I2H_CLEAR_STATS_RSP:
|
|
/*
|
|
* check for timer pop before processing the rsp
|
|
*/
|
|
if (iocfc->stats_busy == BFA_FALSE
|
|
|| iocfc->stats_status == BFA_STATUS_ETIMER)
|
|
break;
|
|
|
|
bfa_timer_stop(&iocfc->stats_timer);
|
|
iocfc->stats_status = BFA_STATUS_OK;
|
|
bfa_cb_queue(bfa, &iocfc->stats_hcb_qe,
|
|
bfa_iocfc_stats_clr_cb, bfa);
|
|
break;
|
|
case BFI_IOCFC_I2H_UPDATEQ_RSP:
|
|
iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK);
|
|
break;
|
|
default:
|
|
bfa_assert(0);
|
|
}
|
|
}
|
|
|
|
#ifndef BFA_BIOS_BUILD
|
|
void
|
|
bfa_adapter_get_attr(struct bfa_s *bfa, struct bfa_adapter_attr_s *ad_attr)
|
|
{
|
|
bfa_ioc_get_adapter_attr(&bfa->ioc, ad_attr);
|
|
}
|
|
|
|
u64
|
|
bfa_adapter_get_id(struct bfa_s *bfa)
|
|
{
|
|
return bfa_ioc_get_adid(&bfa->ioc);
|
|
}
|
|
|
|
void
|
|
bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr)
|
|
{
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
|
|
attr->intr_attr = iocfc->cfginfo->intr_attr;
|
|
attr->config = iocfc->cfg;
|
|
}
|
|
|
|
bfa_status_t
|
|
bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr)
|
|
{
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
struct bfi_iocfc_set_intr_req_s *m;
|
|
|
|
iocfc->cfginfo->intr_attr = *attr;
|
|
if (!bfa_iocfc_is_operational(bfa))
|
|
return BFA_STATUS_OK;
|
|
|
|
m = bfa_reqq_next(bfa, BFA_REQQ_IOC);
|
|
if (!m)
|
|
return BFA_STATUS_DEVBUSY;
|
|
|
|
bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ,
|
|
bfa_lpuid(bfa));
|
|
m->coalesce = attr->coalesce;
|
|
m->delay = bfa_os_htons(attr->delay);
|
|
m->latency = bfa_os_htons(attr->latency);
|
|
|
|
bfa_trc(bfa, attr->delay);
|
|
bfa_trc(bfa, attr->latency);
|
|
|
|
bfa_reqq_produce(bfa, BFA_REQQ_IOC);
|
|
return BFA_STATUS_OK;
|
|
}
|
|
|
|
void
|
|
bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa)
|
|
{
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
|
|
iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1);
|
|
bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa);
|
|
}
|
|
|
|
bfa_status_t
|
|
bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats,
|
|
bfa_cb_ioc_t cbfn, void *cbarg)
|
|
{
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
|
|
if (iocfc->stats_busy) {
|
|
bfa_trc(bfa, iocfc->stats_busy);
|
|
return BFA_STATUS_DEVBUSY;
|
|
}
|
|
|
|
iocfc->stats_busy = BFA_TRUE;
|
|
iocfc->stats_ret = stats;
|
|
iocfc->stats_cbfn = cbfn;
|
|
iocfc->stats_cbarg = cbarg;
|
|
|
|
bfa_iocfc_stats_query(bfa);
|
|
|
|
return BFA_STATUS_OK;
|
|
}
|
|
|
|
bfa_status_t
|
|
bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg)
|
|
{
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
|
|
if (iocfc->stats_busy) {
|
|
bfa_trc(bfa, iocfc->stats_busy);
|
|
return BFA_STATUS_DEVBUSY;
|
|
}
|
|
|
|
iocfc->stats_busy = BFA_TRUE;
|
|
iocfc->stats_cbfn = cbfn;
|
|
iocfc->stats_cbarg = cbarg;
|
|
|
|
bfa_iocfc_stats_clear(bfa);
|
|
return BFA_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* Enable IOC after it is disabled.
|
|
*/
|
|
void
|
|
bfa_iocfc_enable(struct bfa_s *bfa)
|
|
{
|
|
bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0,
|
|
"IOC Enable");
|
|
bfa_ioc_enable(&bfa->ioc);
|
|
}
|
|
|
|
void
|
|
bfa_iocfc_disable(struct bfa_s *bfa)
|
|
{
|
|
bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0,
|
|
"IOC Disable");
|
|
bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE;
|
|
|
|
bfa->rme_process = BFA_FALSE;
|
|
bfa_ioc_disable(&bfa->ioc);
|
|
}
|
|
|
|
|
|
bfa_boolean_t
|
|
bfa_iocfc_is_operational(struct bfa_s *bfa)
|
|
{
|
|
return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone;
|
|
}
|
|
|
|
/**
|
|
* Return boot target port wwns -- read from boot information in flash.
|
|
*/
|
|
void
|
|
bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns)
|
|
{
|
|
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
|
|
struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
|
|
|
|
*nwwns = cfgrsp->bootwwns.nwwns;
|
|
*wwns = cfgrsp->bootwwns.wwn;
|
|
}
|
|
|
|
#endif
|
|
|
|
|