7725ccfda5
Add new driver for Brocade Hardware Signed-off-by: Jing Huang <huangj@brocade.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
493 lines
12 KiB
C
493 lines
12 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 <defs/bfa_defs_cee.h>
|
|
#include <cs/bfa_trc.h>
|
|
#include <cs/bfa_log.h>
|
|
#include <cs/bfa_debug.h>
|
|
#include <cee/bfa_cee.h>
|
|
#include <bfi/bfi_cee.h>
|
|
#include <bfi/bfi.h>
|
|
#include <bfa_ioc.h>
|
|
#include <cna/bfa_cna_trcmod.h>
|
|
|
|
BFA_TRC_FILE(CNA, CEE);
|
|
|
|
#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
|
|
#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc)
|
|
|
|
static void bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg_s *lldp_cfg);
|
|
static void bfa_cee_format_dcbcx_stats(struct bfa_cee_dcbx_stats_s
|
|
*dcbcx_stats);
|
|
static void bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats_s
|
|
*lldp_stats);
|
|
static void bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats_s *cfg_stats);
|
|
static void bfa_cee_format_cee_cfg(void *buffer);
|
|
static void bfa_cee_format_cee_stats(void *buffer);
|
|
|
|
static void
|
|
bfa_cee_format_cee_stats(void *buffer)
|
|
{
|
|
struct bfa_cee_stats_s *cee_stats = buffer;
|
|
bfa_cee_format_dcbcx_stats(&cee_stats->dcbx_stats);
|
|
bfa_cee_format_lldp_stats(&cee_stats->lldp_stats);
|
|
bfa_cee_format_cfg_stats(&cee_stats->cfg_stats);
|
|
}
|
|
|
|
static void
|
|
bfa_cee_format_cee_cfg(void *buffer)
|
|
{
|
|
struct bfa_cee_attr_s *cee_cfg = buffer;
|
|
bfa_cee_format_lldp_cfg(&cee_cfg->lldp_remote);
|
|
}
|
|
|
|
static void
|
|
bfa_cee_format_dcbcx_stats(struct bfa_cee_dcbx_stats_s *dcbcx_stats)
|
|
{
|
|
dcbcx_stats->subtlvs_unrecognized =
|
|
bfa_os_ntohl(dcbcx_stats->subtlvs_unrecognized);
|
|
dcbcx_stats->negotiation_failed =
|
|
bfa_os_ntohl(dcbcx_stats->negotiation_failed);
|
|
dcbcx_stats->remote_cfg_changed =
|
|
bfa_os_ntohl(dcbcx_stats->remote_cfg_changed);
|
|
dcbcx_stats->tlvs_received = bfa_os_ntohl(dcbcx_stats->tlvs_received);
|
|
dcbcx_stats->tlvs_invalid = bfa_os_ntohl(dcbcx_stats->tlvs_invalid);
|
|
dcbcx_stats->seqno = bfa_os_ntohl(dcbcx_stats->seqno);
|
|
dcbcx_stats->ackno = bfa_os_ntohl(dcbcx_stats->ackno);
|
|
dcbcx_stats->recvd_seqno = bfa_os_ntohl(dcbcx_stats->recvd_seqno);
|
|
dcbcx_stats->recvd_ackno = bfa_os_ntohl(dcbcx_stats->recvd_ackno);
|
|
}
|
|
|
|
static void
|
|
bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats_s *lldp_stats)
|
|
{
|
|
lldp_stats->frames_transmitted =
|
|
bfa_os_ntohl(lldp_stats->frames_transmitted);
|
|
lldp_stats->frames_aged_out = bfa_os_ntohl(lldp_stats->frames_aged_out);
|
|
lldp_stats->frames_discarded =
|
|
bfa_os_ntohl(lldp_stats->frames_discarded);
|
|
lldp_stats->frames_in_error = bfa_os_ntohl(lldp_stats->frames_in_error);
|
|
lldp_stats->frames_rcvd = bfa_os_ntohl(lldp_stats->frames_rcvd);
|
|
lldp_stats->tlvs_discarded = bfa_os_ntohl(lldp_stats->tlvs_discarded);
|
|
lldp_stats->tlvs_unrecognized =
|
|
bfa_os_ntohl(lldp_stats->tlvs_unrecognized);
|
|
}
|
|
|
|
static void
|
|
bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats_s *cfg_stats)
|
|
{
|
|
cfg_stats->cee_status_down = bfa_os_ntohl(cfg_stats->cee_status_down);
|
|
cfg_stats->cee_status_up = bfa_os_ntohl(cfg_stats->cee_status_up);
|
|
cfg_stats->cee_hw_cfg_changed =
|
|
bfa_os_ntohl(cfg_stats->cee_hw_cfg_changed);
|
|
cfg_stats->recvd_invalid_cfg =
|
|
bfa_os_ntohl(cfg_stats->recvd_invalid_cfg);
|
|
}
|
|
|
|
static void
|
|
bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg_s *lldp_cfg)
|
|
{
|
|
lldp_cfg->time_to_interval = bfa_os_ntohs(lldp_cfg->time_to_interval);
|
|
lldp_cfg->enabled_system_cap =
|
|
bfa_os_ntohs(lldp_cfg->enabled_system_cap);
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_attr_meminfo()
|
|
*
|
|
*
|
|
* @param[in] void
|
|
*
|
|
* @return Size of DMA region
|
|
*/
|
|
static u32
|
|
bfa_cee_attr_meminfo(void)
|
|
{
|
|
return BFA_ROUNDUP(sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ);
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_stats_meminfo()
|
|
*
|
|
*
|
|
* @param[in] void
|
|
*
|
|
* @return Size of DMA region
|
|
*/
|
|
static u32
|
|
bfa_cee_stats_meminfo(void)
|
|
{
|
|
return BFA_ROUNDUP(sizeof(struct bfa_cee_stats_s), BFA_DMA_ALIGN_SZ);
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_get_attr_isr()
|
|
*
|
|
*
|
|
* @param[in] cee - Pointer to the CEE module
|
|
* status - Return status from the f/w
|
|
*
|
|
* @return void
|
|
*/
|
|
static void
|
|
bfa_cee_get_attr_isr(struct bfa_cee_s *cee, bfa_status_t status)
|
|
{
|
|
cee->get_attr_status = status;
|
|
bfa_trc(cee, 0);
|
|
if (status == BFA_STATUS_OK) {
|
|
bfa_trc(cee, 0);
|
|
/*
|
|
* The requested data has been copied to the DMA area, *process
|
|
* it.
|
|
*/
|
|
memcpy(cee->attr, cee->attr_dma.kva,
|
|
sizeof(struct bfa_cee_attr_s));
|
|
bfa_cee_format_cee_cfg(cee->attr);
|
|
}
|
|
cee->get_attr_pending = BFA_FALSE;
|
|
if (cee->cbfn.get_attr_cbfn) {
|
|
bfa_trc(cee, 0);
|
|
cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status);
|
|
}
|
|
bfa_trc(cee, 0);
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_get_attr_isr()
|
|
*
|
|
*
|
|
* @param[in] cee - Pointer to the CEE module
|
|
* status - Return status from the f/w
|
|
*
|
|
* @return void
|
|
*/
|
|
static void
|
|
bfa_cee_get_stats_isr(struct bfa_cee_s *cee, bfa_status_t status)
|
|
{
|
|
cee->get_stats_status = status;
|
|
bfa_trc(cee, 0);
|
|
if (status == BFA_STATUS_OK) {
|
|
bfa_trc(cee, 0);
|
|
/*
|
|
* The requested data has been copied to the DMA area, process
|
|
* it.
|
|
*/
|
|
memcpy(cee->stats, cee->stats_dma.kva,
|
|
sizeof(struct bfa_cee_stats_s));
|
|
bfa_cee_format_cee_stats(cee->stats);
|
|
}
|
|
cee->get_stats_pending = BFA_FALSE;
|
|
bfa_trc(cee, 0);
|
|
if (cee->cbfn.get_stats_cbfn) {
|
|
bfa_trc(cee, 0);
|
|
cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status);
|
|
}
|
|
bfa_trc(cee, 0);
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_get_attr_isr()
|
|
*
|
|
*
|
|
* @param[in] cee - Pointer to the CEE module
|
|
* status - Return status from the f/w
|
|
*
|
|
* @return void
|
|
*/
|
|
static void
|
|
bfa_cee_reset_stats_isr(struct bfa_cee_s *cee, bfa_status_t status)
|
|
{
|
|
cee->reset_stats_status = status;
|
|
cee->reset_stats_pending = BFA_FALSE;
|
|
if (cee->cbfn.reset_stats_cbfn)
|
|
cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status);
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_meminfo()
|
|
*
|
|
*
|
|
* @param[in] void
|
|
*
|
|
* @return Size of DMA region
|
|
*/
|
|
u32
|
|
bfa_cee_meminfo(void)
|
|
{
|
|
return (bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo());
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_mem_claim()
|
|
*
|
|
*
|
|
* @param[in] cee CEE module pointer
|
|
* dma_kva Kernel Virtual Address of CEE DMA Memory
|
|
* dma_pa Physical Address of CEE DMA Memory
|
|
*
|
|
* @return void
|
|
*/
|
|
void
|
|
bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa)
|
|
{
|
|
cee->attr_dma.kva = dma_kva;
|
|
cee->attr_dma.pa = dma_pa;
|
|
cee->stats_dma.kva = dma_kva + bfa_cee_attr_meminfo();
|
|
cee->stats_dma.pa = dma_pa + bfa_cee_attr_meminfo();
|
|
cee->attr = (struct bfa_cee_attr_s *)dma_kva;
|
|
cee->stats =
|
|
(struct bfa_cee_stats_s *)(dma_kva + bfa_cee_attr_meminfo());
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_get_attr()
|
|
*
|
|
* Send the request to the f/w to fetch CEE attributes.
|
|
*
|
|
* @param[in] Pointer to the CEE module data structure.
|
|
*
|
|
* @return Status
|
|
*/
|
|
|
|
bfa_status_t
|
|
bfa_cee_get_attr(struct bfa_cee_s *cee, struct bfa_cee_attr_s *attr,
|
|
bfa_cee_get_attr_cbfn_t cbfn, void *cbarg)
|
|
{
|
|
struct bfi_cee_get_req_s *cmd;
|
|
|
|
bfa_assert((cee != NULL) && (cee->ioc != NULL));
|
|
bfa_trc(cee, 0);
|
|
if (!bfa_ioc_is_operational(cee->ioc)) {
|
|
bfa_trc(cee, 0);
|
|
return BFA_STATUS_IOC_FAILURE;
|
|
}
|
|
if (cee->get_attr_pending == BFA_TRUE) {
|
|
bfa_trc(cee, 0);
|
|
return BFA_STATUS_DEVBUSY;
|
|
}
|
|
cee->get_attr_pending = BFA_TRUE;
|
|
cmd = (struct bfi_cee_get_req_s *)cee->get_cfg_mb.msg;
|
|
cee->attr = attr;
|
|
cee->cbfn.get_attr_cbfn = cbfn;
|
|
cee->cbfn.get_attr_cbarg = cbarg;
|
|
bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ,
|
|
bfa_ioc_portid(cee->ioc));
|
|
bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa);
|
|
bfa_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb);
|
|
bfa_trc(cee, 0);
|
|
|
|
return BFA_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_get_stats()
|
|
*
|
|
* Send the request to the f/w to fetch CEE statistics.
|
|
*
|
|
* @param[in] Pointer to the CEE module data structure.
|
|
*
|
|
* @return Status
|
|
*/
|
|
|
|
bfa_status_t
|
|
bfa_cee_get_stats(struct bfa_cee_s *cee, struct bfa_cee_stats_s *stats,
|
|
bfa_cee_get_stats_cbfn_t cbfn, void *cbarg)
|
|
{
|
|
struct bfi_cee_get_req_s *cmd;
|
|
|
|
bfa_assert((cee != NULL) && (cee->ioc != NULL));
|
|
|
|
if (!bfa_ioc_is_operational(cee->ioc)) {
|
|
bfa_trc(cee, 0);
|
|
return BFA_STATUS_IOC_FAILURE;
|
|
}
|
|
if (cee->get_stats_pending == BFA_TRUE) {
|
|
bfa_trc(cee, 0);
|
|
return BFA_STATUS_DEVBUSY;
|
|
}
|
|
cee->get_stats_pending = BFA_TRUE;
|
|
cmd = (struct bfi_cee_get_req_s *)cee->get_stats_mb.msg;
|
|
cee->stats = stats;
|
|
cee->cbfn.get_stats_cbfn = cbfn;
|
|
cee->cbfn.get_stats_cbarg = cbarg;
|
|
bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ,
|
|
bfa_ioc_portid(cee->ioc));
|
|
bfa_dma_be_addr_set(cmd->dma_addr, cee->stats_dma.pa);
|
|
bfa_ioc_mbox_queue(cee->ioc, &cee->get_stats_mb);
|
|
bfa_trc(cee, 0);
|
|
|
|
return BFA_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_reset_stats()
|
|
*
|
|
*
|
|
* @param[in] Pointer to the CEE module data structure.
|
|
*
|
|
* @return Status
|
|
*/
|
|
|
|
bfa_status_t
|
|
bfa_cee_reset_stats(struct bfa_cee_s *cee, bfa_cee_reset_stats_cbfn_t cbfn,
|
|
void *cbarg)
|
|
{
|
|
struct bfi_cee_reset_stats_s *cmd;
|
|
|
|
bfa_assert((cee != NULL) && (cee->ioc != NULL));
|
|
if (!bfa_ioc_is_operational(cee->ioc)) {
|
|
bfa_trc(cee, 0);
|
|
return BFA_STATUS_IOC_FAILURE;
|
|
}
|
|
if (cee->reset_stats_pending == BFA_TRUE) {
|
|
bfa_trc(cee, 0);
|
|
return BFA_STATUS_DEVBUSY;
|
|
}
|
|
cee->reset_stats_pending = BFA_TRUE;
|
|
cmd = (struct bfi_cee_reset_stats_s *)cee->reset_stats_mb.msg;
|
|
cee->cbfn.reset_stats_cbfn = cbfn;
|
|
cee->cbfn.reset_stats_cbarg = cbarg;
|
|
bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS,
|
|
bfa_ioc_portid(cee->ioc));
|
|
bfa_ioc_mbox_queue(cee->ioc, &cee->reset_stats_mb);
|
|
bfa_trc(cee, 0);
|
|
return BFA_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_isrs()
|
|
*
|
|
*
|
|
* @param[in] Pointer to the CEE module data structure.
|
|
*
|
|
* @return void
|
|
*/
|
|
|
|
void
|
|
bfa_cee_isr(void *cbarg, struct bfi_mbmsg_s *m)
|
|
{
|
|
union bfi_cee_i2h_msg_u *msg;
|
|
struct bfi_cee_get_rsp_s *get_rsp;
|
|
struct bfa_cee_s *cee = (struct bfa_cee_s *)cbarg;
|
|
msg = (union bfi_cee_i2h_msg_u *)m;
|
|
get_rsp = (struct bfi_cee_get_rsp_s *)m;
|
|
bfa_trc(cee, msg->mh.msg_id);
|
|
switch (msg->mh.msg_id) {
|
|
case BFI_CEE_I2H_GET_CFG_RSP:
|
|
bfa_trc(cee, get_rsp->cmd_status);
|
|
bfa_cee_get_attr_isr(cee, get_rsp->cmd_status);
|
|
break;
|
|
case BFI_CEE_I2H_GET_STATS_RSP:
|
|
bfa_cee_get_stats_isr(cee, get_rsp->cmd_status);
|
|
break;
|
|
case BFI_CEE_I2H_RESET_STATS_RSP:
|
|
bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status);
|
|
break;
|
|
default:
|
|
bfa_assert(0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_hbfail()
|
|
*
|
|
*
|
|
* @param[in] Pointer to the CEE module data structure.
|
|
*
|
|
* @return void
|
|
*/
|
|
|
|
void
|
|
bfa_cee_hbfail(void *arg)
|
|
{
|
|
struct bfa_cee_s *cee;
|
|
cee = (struct bfa_cee_s *)arg;
|
|
|
|
if (cee->get_attr_pending == BFA_TRUE) {
|
|
cee->get_attr_status = BFA_STATUS_FAILED;
|
|
cee->get_attr_pending = BFA_FALSE;
|
|
if (cee->cbfn.get_attr_cbfn) {
|
|
cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg,
|
|
BFA_STATUS_FAILED);
|
|
}
|
|
}
|
|
if (cee->get_stats_pending == BFA_TRUE) {
|
|
cee->get_stats_status = BFA_STATUS_FAILED;
|
|
cee->get_stats_pending = BFA_FALSE;
|
|
if (cee->cbfn.get_stats_cbfn) {
|
|
cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg,
|
|
BFA_STATUS_FAILED);
|
|
}
|
|
}
|
|
if (cee->reset_stats_pending == BFA_TRUE) {
|
|
cee->reset_stats_status = BFA_STATUS_FAILED;
|
|
cee->reset_stats_pending = BFA_FALSE;
|
|
if (cee->cbfn.reset_stats_cbfn) {
|
|
cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg,
|
|
BFA_STATUS_FAILED);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_attach()
|
|
*
|
|
*
|
|
* @param[in] cee - Pointer to the CEE module data structure
|
|
* ioc - Pointer to the ioc module data structure
|
|
* dev - Pointer to the device driver module data structure
|
|
* The device driver specific mbox ISR functions have
|
|
* this pointer as one of the parameters.
|
|
* trcmod -
|
|
* logmod -
|
|
*
|
|
* @return void
|
|
*/
|
|
void
|
|
bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, void *dev,
|
|
struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod)
|
|
{
|
|
bfa_assert(cee != NULL);
|
|
cee->dev = dev;
|
|
cee->trcmod = trcmod;
|
|
cee->logmod = logmod;
|
|
cee->ioc = ioc;
|
|
|
|
bfa_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee);
|
|
bfa_ioc_hbfail_init(&cee->hbfail, bfa_cee_hbfail, cee);
|
|
bfa_ioc_hbfail_register(cee->ioc, &cee->hbfail);
|
|
bfa_trc(cee, 0);
|
|
}
|
|
|
|
/**
|
|
* bfa_cee_detach()
|
|
*
|
|
*
|
|
* @param[in] cee - Pointer to the CEE module data structure
|
|
*
|
|
* @return void
|
|
*/
|
|
void
|
|
bfa_cee_detach(struct bfa_cee_s *cee)
|
|
{
|
|
/*
|
|
* For now, just check if there is some ioctl pending and mark that as
|
|
* failed?
|
|
*/
|
|
/* bfa_cee_hbfail(cee); */
|
|
}
|