linux/drivers/scsi/bfa/bfa_core.c
Jing Huang 293f82d59e [SCSI] bfa: enable new hardware
This patch enables support of new mezzanine cards for HP and IBM blade server.

- Add new pciids for HP and IBM mezzanine card.
- Add a new firmware image for HP mezzanine card, which is running in
  FC only mode. Rename firmware image to reflect the difference. Change the
  firmware download code accordingly for the above changes.

Signed-off-by: Jing Huang <huangj@brocade.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
2010-07-27 12:04:03 -05:00

444 lines
11 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 <bfa.h>
#include <defs/bfa_defs_pci.h>
#include <cs/bfa_debug.h>
#include <bfa_iocfc.h>
#define DEF_CFG_NUM_FABRICS 1
#define DEF_CFG_NUM_LPORTS 256
#define DEF_CFG_NUM_CQS 4
#define DEF_CFG_NUM_IOIM_REQS (BFA_IOIM_MAX)
#define DEF_CFG_NUM_TSKIM_REQS 128
#define DEF_CFG_NUM_FCXP_REQS 64
#define DEF_CFG_NUM_UF_BUFS 64
#define DEF_CFG_NUM_RPORTS 1024
#define DEF_CFG_NUM_ITNIMS (DEF_CFG_NUM_RPORTS)
#define DEF_CFG_NUM_TINS 256
#define DEF_CFG_NUM_SGPGS 2048
#define DEF_CFG_NUM_REQQ_ELEMS 256
#define DEF_CFG_NUM_RSPQ_ELEMS 64
#define DEF_CFG_NUM_SBOOT_TGTS 16
#define DEF_CFG_NUM_SBOOT_LUNS 16
/**
* Use this function query the memory requirement of the BFA library.
* This function needs to be called before bfa_attach() to get the
* memory required of the BFA layer for a given driver configuration.
*
* This call will fail, if the cap is out of range compared to pre-defined
* values within the BFA library
*
* @param[in] cfg - pointer to bfa_ioc_cfg_t. Driver layer should indicate
* its configuration in this structure.
* The default values for struct bfa_iocfc_cfg_s can be
* fetched using bfa_cfg_get_default() API.
*
* If cap's boundary check fails, the library will use
* the default bfa_cap_t values (and log a warning msg).
*
* @param[out] meminfo - pointer to bfa_meminfo_t. This content
* indicates the memory type (see bfa_mem_type_t) and
* amount of memory required.
*
* Driver should allocate the memory, populate the
* starting address for each block and provide the same
* structure as input parameter to bfa_attach() call.
*
* @return void
*
* Special Considerations: @note
*/
void
bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo)
{
int i;
u32 km_len = 0, dm_len = 0;
bfa_assert((cfg != NULL) && (meminfo != NULL));
bfa_os_memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s));
meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_type =
BFA_MEM_TYPE_KVA;
meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_type =
BFA_MEM_TYPE_DMA;
bfa_iocfc_meminfo(cfg, &km_len, &dm_len);
for (i = 0; hal_mods[i]; i++)
hal_mods[i]->meminfo(cfg, &km_len, &dm_len);
dm_len += bfa_port_meminfo();
meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_len = km_len;
meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len;
}
static void
bfa_com_port_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi)
{
struct bfa_port_s *port = &bfa->modules.port;
uint32_t dm_len;
uint8_t *dm_kva;
uint64_t dm_pa;
dm_len = bfa_port_meminfo();
dm_kva = bfa_meminfo_dma_virt(mi);
dm_pa = bfa_meminfo_dma_phys(mi);
memset(port, 0, sizeof(struct bfa_port_s));
bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod, bfa->logm);
bfa_port_mem_claim(port, dm_kva, dm_pa);
bfa_meminfo_dma_virt(mi) = dm_kva + dm_len;
bfa_meminfo_dma_phys(mi) = dm_pa + dm_len;
}
/**
* Use this function to do attach the driver instance with the BFA
* library. This function will not trigger any HW initialization
* process (which will be done in bfa_init() call)
*
* This call will fail, if the cap is out of range compared to
* pre-defined values within the BFA library
*
* @param[out] bfa Pointer to bfa_t.
* @param[in] bfad Opaque handle back to the driver's IOC structure
* @param[in] cfg Pointer to bfa_ioc_cfg_t. Should be same structure
* that was used in bfa_cfg_get_meminfo().
* @param[in] meminfo Pointer to bfa_meminfo_t. The driver should
* use the bfa_cfg_get_meminfo() call to
* find the memory blocks required, allocate the
* required memory and provide the starting addresses.
* @param[in] pcidev pointer to struct bfa_pcidev_s
*
* @return
* void
*
* Special Considerations:
*
* @note
*
*/
void
bfa_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;
struct bfa_mem_elem_s *melem;
bfa->fcs = BFA_FALSE;
bfa_assert((cfg != NULL) && (meminfo != NULL));
/**
* initialize all memory pointers for iterative allocation
*/
for (i = 0; i < BFA_MEM_TYPE_MAX; i++) {
melem = meminfo->meminfo + i;
melem->kva_curp = melem->kva;
melem->dma_curp = melem->dma;
}
bfa_iocfc_attach(bfa, bfad, cfg, meminfo, pcidev);
for (i = 0; hal_mods[i]; i++)
hal_mods[i]->attach(bfa, bfad, cfg, meminfo, pcidev);
bfa_com_port_attach(bfa, meminfo);
}
/**
* Use this function to delete a BFA IOC. IOC should be stopped (by
* calling bfa_stop()) before this function call.
*
* @param[in] bfa - pointer to bfa_t.
*
* @return
* void
*
* Special Considerations:
*
* @note
*/
void
bfa_detach(struct bfa_s *bfa)
{
int i;
for (i = 0; hal_mods[i]; i++)
hal_mods[i]->detach(bfa);
bfa_iocfc_detach(bfa);
}
void
bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod)
{
bfa->trcmod = trcmod;
}
void
bfa_init_log(struct bfa_s *bfa, struct bfa_log_mod_s *logmod)
{
bfa->logm = logmod;
}
void
bfa_init_aen(struct bfa_s *bfa, struct bfa_aen_s *aen)
{
bfa->aen = aen;
}
void
bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog)
{
bfa->plog = plog;
}
/**
* Initialize IOC.
*
* This function will return immediately, when the IOC initialization is
* completed, the bfa_cb_init() will be called.
*
* @param[in] bfa instance
*
* @return void
*
* Special Considerations:
*
* @note
* When this function returns, the driver should register the interrupt service
* routine(s) and enable the device interrupts. If this is not done,
* bfa_cb_init() will never get called
*/
void
bfa_init(struct bfa_s *bfa)
{
bfa_iocfc_init(bfa);
}
/**
* Use this function initiate the IOC configuration setup. This function
* will return immediately.
*
* @param[in] bfa instance
*
* @return None
*/
void
bfa_start(struct bfa_s *bfa)
{
bfa_iocfc_start(bfa);
}
/**
* Use this function quiese the IOC. This function will return immediately,
* when the IOC is actually stopped, the bfa_cb_stop() will be called.
*
* @param[in] bfa - pointer to bfa_t.
*
* @return None
*
* Special Considerations:
* bfa_cb_stop() could be called before or after bfa_stop() returns.
*
* @note
* In case of any failure, we could handle it automatically by doing a
* reset and then succeed the bfa_stop() call.
*/
void
bfa_stop(struct bfa_s *bfa)
{
bfa_iocfc_stop(bfa);
}
void
bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q)
{
INIT_LIST_HEAD(comp_q);
list_splice_tail_init(&bfa->comp_q, comp_q);
}
void
bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q)
{
struct list_head *qe;
struct list_head *qen;
struct bfa_cb_qe_s *hcb_qe;
list_for_each_safe(qe, qen, comp_q) {
hcb_qe = (struct bfa_cb_qe_s *) qe;
hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE);
}
}
void
bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q)
{
struct list_head *qe;
struct bfa_cb_qe_s *hcb_qe;
while (!list_empty(comp_q)) {
bfa_q_deq(comp_q, &qe);
hcb_qe = (struct bfa_cb_qe_s *) qe;
hcb_qe->cbfn(hcb_qe->cbarg, BFA_FALSE);
}
}
void
bfa_attach_fcs(struct bfa_s *bfa)
{
bfa->fcs = BFA_TRUE;
}
/**
* Periodic timer heart beat from driver
*/
void
bfa_timer_tick(struct bfa_s *bfa)
{
bfa_timer_beat(&bfa->timer_mod);
}
#ifndef BFA_BIOS_BUILD
/**
* Return the list of PCI vendor/device id lists supported by this
* BFA instance.
*/
void
bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids)
{
static struct bfa_pciid_s __pciids[] = {
{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G2P},
{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G1P},
{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT},
{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT_FC},
};
*npciids = sizeof(__pciids) / sizeof(__pciids[0]);
*pciids = __pciids;
}
/**
* Use this function query the default struct bfa_iocfc_cfg_s value (compiled
* into BFA layer). The OS driver can then turn back and overwrite entries that
* have been configured by the user.
*
* @param[in] cfg - pointer to bfa_ioc_cfg_t
*
* @return
* void
*
* Special Considerations:
* note
*/
void
bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg)
{
cfg->fwcfg.num_fabrics = DEF_CFG_NUM_FABRICS;
cfg->fwcfg.num_lports = DEF_CFG_NUM_LPORTS;
cfg->fwcfg.num_rports = DEF_CFG_NUM_RPORTS;
cfg->fwcfg.num_ioim_reqs = DEF_CFG_NUM_IOIM_REQS;
cfg->fwcfg.num_tskim_reqs = DEF_CFG_NUM_TSKIM_REQS;
cfg->fwcfg.num_fcxp_reqs = DEF_CFG_NUM_FCXP_REQS;
cfg->fwcfg.num_uf_bufs = DEF_CFG_NUM_UF_BUFS;
cfg->fwcfg.num_cqs = DEF_CFG_NUM_CQS;
cfg->drvcfg.num_reqq_elems = DEF_CFG_NUM_REQQ_ELEMS;
cfg->drvcfg.num_rspq_elems = DEF_CFG_NUM_RSPQ_ELEMS;
cfg->drvcfg.num_sgpgs = DEF_CFG_NUM_SGPGS;
cfg->drvcfg.num_sboot_tgts = DEF_CFG_NUM_SBOOT_TGTS;
cfg->drvcfg.num_sboot_luns = DEF_CFG_NUM_SBOOT_LUNS;
cfg->drvcfg.path_tov = BFA_FCPIM_PATHTOV_DEF;
cfg->drvcfg.ioc_recover = BFA_FALSE;
cfg->drvcfg.delay_comp = BFA_FALSE;
}
void
bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg)
{
bfa_cfg_get_default(cfg);
cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN;
cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN;
cfg->fwcfg.num_fcxp_reqs = BFA_FCXP_MIN;
cfg->fwcfg.num_uf_bufs = BFA_UF_MIN;
cfg->fwcfg.num_rports = BFA_RPORT_MIN;
cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN;
cfg->drvcfg.num_reqq_elems = BFA_REQQ_NELEMS_MIN;
cfg->drvcfg.num_rspq_elems = BFA_RSPQ_NELEMS_MIN;
cfg->drvcfg.min_cfg = BFA_TRUE;
}
void
bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr)
{
bfa_ioc_get_attr(&bfa->ioc, ioc_attr);
}
/**
* Retrieve firmware trace information on IOC failure.
*/
bfa_status_t
bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen)
{
return bfa_ioc_debug_fwsave(&bfa->ioc, trcdata, trclen);
}
/**
* Clear the saved firmware trace information of an IOC.
*/
void
bfa_debug_fwsave_clear(struct bfa_s *bfa)
{
bfa_ioc_debug_fwsave_clear(&bfa->ioc);
}
/**
* Fetch firmware trace data.
*
* @param[in] bfa BFA instance
* @param[out] trcdata Firmware trace buffer
* @param[in,out] trclen Firmware trace buffer len
*
* @retval BFA_STATUS_OK Firmware trace is fetched.
* @retval BFA_STATUS_INPROGRESS Firmware trace fetch is in progress.
*/
bfa_status_t
bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen)
{
return bfa_ioc_debug_fwtrc(&bfa->ioc, trcdata, trclen);
}
/**
* Reset hw semaphore & usage cnt regs and initialize.
*/
void
bfa_chip_reset(struct bfa_s *bfa)
{
bfa_ioc_ownership_reset(&bfa->ioc);
bfa_ioc_pll_init(&bfa->ioc);
}
#endif