[SCSI] bfa: Added HBA diagnostics support.

- Added diagnostics sub-module to BFA.
- Implemented interface to perform memtest/loopback test
  and some other diagnostics tests.

Signed-off-by: Krishna Gudipati <kgudipat@brocade.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
Krishna Gudipati 2011-06-24 20:28:17 -07:00 committed by James Bottomley
parent 5a54b1d576
commit 3d7fc66dcd
11 changed files with 1665 additions and 9 deletions

View File

@ -25,6 +25,7 @@ BFA_TRC_FILE(HAL, CORE);
* BFA module list terminated by NULL
*/
static struct bfa_module_s *hal_mods[] = {
&hal_mod_fcdiag,
&hal_mod_sgpg,
&hal_mod_fcport,
&hal_mod_fcxp,
@ -41,7 +42,7 @@ static struct bfa_module_s *hal_mods[] = {
static bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = {
bfa_isr_unhandled, /* NONE */
bfa_isr_unhandled, /* BFI_MC_IOC */
bfa_isr_unhandled, /* BFI_MC_DIAG */
bfa_fcdiag_intr, /* BFI_MC_DIAG */
bfa_isr_unhandled, /* BFI_MC_FLASH */
bfa_isr_unhandled, /* BFI_MC_CEE */
bfa_fcport_isr, /* BFI_MC_FCPORT */
@ -143,6 +144,16 @@ bfa_com_flash_attach(struct bfa_s *bfa, bfa_boolean_t mincfg)
flash_dma->dma_curp, mincfg);
}
static void
bfa_com_diag_attach(struct bfa_s *bfa)
{
struct bfa_diag_s *diag = BFA_DIAG_MOD(bfa);
struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa);
bfa_diag_attach(diag, &bfa->ioc, bfa, bfa_fcport_beacon, bfa->trcmod);
bfa_diag_memclaim(diag, diag_dma->kva_curp, diag_dma->dma_curp);
}
/*
* BFA IOC FC related definitions
*/
@ -1383,6 +1394,7 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
struct bfa_mem_dma_s *cee_dma = BFA_MEM_CEE_DMA(bfa);
struct bfa_mem_dma_s *sfp_dma = BFA_MEM_SFP_DMA(bfa);
struct bfa_mem_dma_s *flash_dma = BFA_MEM_FLASH_DMA(bfa);
struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa);
WARN_ON((cfg == NULL) || (meminfo == NULL));
@ -1404,6 +1416,7 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
bfa_mem_dma_setup(meminfo, sfp_dma, bfa_sfp_meminfo());
bfa_mem_dma_setup(meminfo, flash_dma,
bfa_flash_meminfo(cfg->drvcfg.min_cfg));
bfa_mem_dma_setup(meminfo, diag_dma, bfa_diag_meminfo());
}
/*
@ -1474,6 +1487,7 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
bfa_com_cee_attach(bfa);
bfa_com_sfp_attach(bfa);
bfa_com_flash_attach(bfa, cfg->drvcfg.min_cfg);
bfa_com_diag_attach(bfa);
}
/*

View File

@ -132,7 +132,9 @@ enum bfa_status {
BFA_STATUS_EPROTOCOL = 6, /* Protocol error */
BFA_STATUS_SFP_UNSUPP = 10, /* Unsupported SFP - Replace SFP */
BFA_STATUS_UNKNOWN_VFID = 11, /* VF_ID not found */
BFA_STATUS_DATACORRUPTED = 12, /* Diag returned data corrupted */
BFA_STATUS_DEVBUSY = 13, /* Device busy - Retry operation */
BFA_STATUS_HDMA_FAILED = 16, /* Host dma failed contact support */
BFA_STATUS_FLASH_BAD_LEN = 17, /* Flash bad length */
BFA_STATUS_UNKNOWN_LWWN = 18, /* LPORT PWWN not found */
BFA_STATUS_UNKNOWN_RWWN = 19, /* RPORT PWWN not found */
@ -140,19 +142,25 @@ enum bfa_status {
BFA_STATUS_VPORT_MAX = 22, /* Reached max VPORT supported limit */
BFA_STATUS_UNSUPP_SPEED = 23, /* Invalid Speed Check speed setting */
BFA_STATUS_INVLD_DFSZ = 24, /* Invalid Max data field size */
BFA_STATUS_CMD_NOTSUPP = 26, /* Command/API not supported */
BFA_STATUS_FABRIC_RJT = 29, /* Reject from attached fabric */
BFA_STATUS_PORT_OFFLINE = 34, /* Port is not online */
BFA_STATUS_VPORT_WWN_BP = 46, /* WWN is same as base port's WWN */
BFA_STATUS_PORT_NOT_DISABLED = 47, /* Port not disabled disable port */
BFA_STATUS_NO_FCPIM_NEXUS = 52, /* No FCP Nexus exists with the rport */
BFA_STATUS_IOC_FAILURE = 56, /* IOC failure - Retry, if persists
* contact support */
BFA_STATUS_INVALID_WWN = 57, /* Invalid WWN */
BFA_STATUS_ADAPTER_ENABLED = 60, /* Adapter is not disabled */
BFA_STATUS_IOC_NON_OP = 61, /* IOC is not operational */
BFA_STATUS_VERSION_FAIL = 70, /* Application/Driver version mismatch */
BFA_STATUS_DIAG_BUSY = 71, /* diag busy */
BFA_STATUS_BEACON_ON = 72, /* Port Beacon already on */
BFA_STATUS_ENOFSAVE = 78, /* No saved firmware trace */
BFA_STATUS_IOC_DISABLED = 82, /* IOC is already disabled */
BFA_STATUS_NO_SFP_DEV = 89, /* No SFP device check or replace SFP */
BFA_STATUS_MEMTEST_FAILED = 90, /* Memory test failed contact support */
BFA_STATUS_LEDTEST_OP = 109, /* LED test is operating */
BFA_STATUS_INVALID_MAC = 134, /* Invalid MAC address */
BFA_STATUS_PBC = 154, /* Operation not allowed for pre-boot
* configuration */
@ -881,6 +889,56 @@ struct bfa_flash_attr_s {
struct bfa_flash_part_attr_s part[BFA_FLASH_PART_MAX];
};
/*
* DIAG module specific
*/
#define LB_PATTERN_DEFAULT 0xB5B5B5B5
#define QTEST_CNT_DEFAULT 10
#define QTEST_PAT_DEFAULT LB_PATTERN_DEFAULT
struct bfa_diag_memtest_s {
u8 algo;
u8 rsvd[7];
};
struct bfa_diag_memtest_result {
u32 status;
u32 addr;
u32 exp; /* expect value read from reg */
u32 act; /* actually value read */
u32 err_status; /* error status reg */
u32 err_status1; /* extra error info reg */
u32 err_addr; /* error address reg */
u8 algo;
u8 rsv[3];
};
struct bfa_diag_loopback_result_s {
u32 numtxmfrm; /* no. of transmit frame */
u32 numosffrm; /* no. of outstanding frame */
u32 numrcvfrm; /* no. of received good frame */
u32 badfrminf; /* mis-match info */
u32 badfrmnum; /* mis-match fram number */
u8 status; /* loopback test result */
u8 rsvd[3];
};
struct bfa_diag_ledtest_s {
u32 cmd; /* bfa_led_op_t */
u32 color; /* bfa_led_color_t */
u16 freq; /* no. of blinks every 10 secs */
u8 led; /* bitmap of LEDs to be tested */
u8 rsvd[5];
};
struct bfa_diag_loopback_s {
u32 loopcnt;
u32 pattern;
u8 lb_mode; /* bfa_port_opmode_t */
u8 speed; /* bfa_port_speed_t */
u8 rsvd[2];
};
#pragma pack()
#endif /* __BFA_DEFS_H__ */

View File

@ -4315,3 +4315,583 @@ bfa_flash_read_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type,
return BFA_STATUS_OK;
}
/*
* DIAG module specific
*/
#define BFA_DIAG_MEMTEST_TOV 50000 /* memtest timeout in msec */
#define BFA_DIAG_FWPING_TOV 1000 /* msec */
/* IOC event handler */
static void
bfa_diag_notify(void *diag_arg, enum bfa_ioc_event_e event)
{
struct bfa_diag_s *diag = diag_arg;
bfa_trc(diag, event);
bfa_trc(diag, diag->block);
bfa_trc(diag, diag->fwping.lock);
bfa_trc(diag, diag->tsensor.lock);
switch (event) {
case BFA_IOC_E_DISABLED:
case BFA_IOC_E_FAILED:
if (diag->fwping.lock) {
diag->fwping.status = BFA_STATUS_IOC_FAILURE;
diag->fwping.cbfn(diag->fwping.cbarg,
diag->fwping.status);
diag->fwping.lock = 0;
}
if (diag->tsensor.lock) {
diag->tsensor.status = BFA_STATUS_IOC_FAILURE;
diag->tsensor.cbfn(diag->tsensor.cbarg,
diag->tsensor.status);
diag->tsensor.lock = 0;
}
if (diag->block) {
if (diag->timer_active) {
bfa_timer_stop(&diag->timer);
diag->timer_active = 0;
}
diag->status = BFA_STATUS_IOC_FAILURE;
diag->cbfn(diag->cbarg, diag->status);
diag->block = 0;
}
break;
default:
break;
}
}
static void
bfa_diag_memtest_done(void *cbarg)
{
struct bfa_diag_s *diag = cbarg;
struct bfa_ioc_s *ioc = diag->ioc;
struct bfa_diag_memtest_result *res = diag->result;
u32 loff = BFI_BOOT_MEMTEST_RES_ADDR;
u32 pgnum, pgoff, i;
pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);
pgoff = PSS_SMEM_PGOFF(loff);
writel(pgnum, ioc->ioc_regs.host_page_num_fn);
for (i = 0; i < (sizeof(struct bfa_diag_memtest_result) /
sizeof(u32)); i++) {
/* read test result from smem */
*((u32 *) res + i) =
bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);
loff += sizeof(u32);
}
/* Reset IOC fwstates to BFI_IOC_UNINIT */
bfa_ioc_reset_fwstate(ioc);
res->status = swab32(res->status);
bfa_trc(diag, res->status);
if (res->status == BFI_BOOT_MEMTEST_RES_SIG)
diag->status = BFA_STATUS_OK;
else {
diag->status = BFA_STATUS_MEMTEST_FAILED;
res->addr = swab32(res->addr);
res->exp = swab32(res->exp);
res->act = swab32(res->act);
res->err_status = swab32(res->err_status);
res->err_status1 = swab32(res->err_status1);
res->err_addr = swab32(res->err_addr);
bfa_trc(diag, res->addr);
bfa_trc(diag, res->exp);
bfa_trc(diag, res->act);
bfa_trc(diag, res->err_status);
bfa_trc(diag, res->err_status1);
bfa_trc(diag, res->err_addr);
}
diag->timer_active = 0;
diag->cbfn(diag->cbarg, diag->status);
diag->block = 0;
}
/*
* Firmware ping
*/
/*
* Perform DMA test directly
*/
static void
diag_fwping_send(struct bfa_diag_s *diag)
{
struct bfi_diag_fwping_req_s *fwping_req;
u32 i;
bfa_trc(diag, diag->fwping.dbuf_pa);
/* fill DMA area with pattern */
for (i = 0; i < (BFI_DIAG_DMA_BUF_SZ >> 2); i++)
*((u32 *)diag->fwping.dbuf_kva + i) = diag->fwping.data;
/* Fill mbox msg */
fwping_req = (struct bfi_diag_fwping_req_s *)diag->fwping.mbcmd.msg;
/* Setup SG list */
bfa_alen_set(&fwping_req->alen, BFI_DIAG_DMA_BUF_SZ,
diag->fwping.dbuf_pa);
/* Set up dma count */
fwping_req->count = cpu_to_be32(diag->fwping.count);
/* Set up data pattern */
fwping_req->data = diag->fwping.data;
/* build host command */
bfi_h2i_set(fwping_req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_FWPING,
bfa_ioc_portid(diag->ioc));
/* send mbox cmd */
bfa_ioc_mbox_queue(diag->ioc, &diag->fwping.mbcmd);
}
static void
diag_fwping_comp(struct bfa_diag_s *diag,
struct bfi_diag_fwping_rsp_s *diag_rsp)
{
u32 rsp_data = diag_rsp->data;
u8 rsp_dma_status = diag_rsp->dma_status;
bfa_trc(diag, rsp_data);
bfa_trc(diag, rsp_dma_status);
if (rsp_dma_status == BFA_STATUS_OK) {
u32 i, pat;
pat = (diag->fwping.count & 0x1) ? ~(diag->fwping.data) :
diag->fwping.data;
/* Check mbox data */
if (diag->fwping.data != rsp_data) {
bfa_trc(diag, rsp_data);
diag->fwping.result->dmastatus =
BFA_STATUS_DATACORRUPTED;
diag->fwping.status = BFA_STATUS_DATACORRUPTED;
diag->fwping.cbfn(diag->fwping.cbarg,
diag->fwping.status);
diag->fwping.lock = 0;
return;
}
/* Check dma pattern */
for (i = 0; i < (BFI_DIAG_DMA_BUF_SZ >> 2); i++) {
if (*((u32 *)diag->fwping.dbuf_kva + i) != pat) {
bfa_trc(diag, i);
bfa_trc(diag, pat);
bfa_trc(diag,
*((u32 *)diag->fwping.dbuf_kva + i));
diag->fwping.result->dmastatus =
BFA_STATUS_DATACORRUPTED;
diag->fwping.status = BFA_STATUS_DATACORRUPTED;
diag->fwping.cbfn(diag->fwping.cbarg,
diag->fwping.status);
diag->fwping.lock = 0;
return;
}
}
diag->fwping.result->dmastatus = BFA_STATUS_OK;
diag->fwping.status = BFA_STATUS_OK;
diag->fwping.cbfn(diag->fwping.cbarg, diag->fwping.status);
diag->fwping.lock = 0;
} else {
diag->fwping.status = BFA_STATUS_HDMA_FAILED;
diag->fwping.cbfn(diag->fwping.cbarg, diag->fwping.status);
diag->fwping.lock = 0;
}
}
/*
* Temperature Sensor
*/
static void
diag_tempsensor_send(struct bfa_diag_s *diag)
{
struct bfi_diag_ts_req_s *msg;
msg = (struct bfi_diag_ts_req_s *)diag->tsensor.mbcmd.msg;
bfa_trc(diag, msg->temp);
/* build host command */
bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_TEMPSENSOR,
bfa_ioc_portid(diag->ioc));
/* send mbox cmd */
bfa_ioc_mbox_queue(diag->ioc, &diag->tsensor.mbcmd);
}
static void
diag_tempsensor_comp(struct bfa_diag_s *diag, bfi_diag_ts_rsp_t *rsp)
{
if (!diag->tsensor.lock) {
/* receiving response after ioc failure */
bfa_trc(diag, diag->tsensor.lock);
return;
}
/*
* ASIC junction tempsensor is a reg read operation
* it will always return OK
*/
diag->tsensor.temp->temp = be16_to_cpu(rsp->temp);
diag->tsensor.temp->ts_junc = rsp->ts_junc;
diag->tsensor.temp->ts_brd = rsp->ts_brd;
diag->tsensor.temp->status = BFA_STATUS_OK;
if (rsp->ts_brd) {
if (rsp->status == BFA_STATUS_OK) {
diag->tsensor.temp->brd_temp =
be16_to_cpu(rsp->brd_temp);
} else {
bfa_trc(diag, rsp->status);
diag->tsensor.temp->brd_temp = 0;
diag->tsensor.temp->status = BFA_STATUS_DEVBUSY;
}
}
bfa_trc(diag, rsp->ts_junc);
bfa_trc(diag, rsp->temp);
bfa_trc(diag, rsp->ts_brd);
bfa_trc(diag, rsp->brd_temp);
diag->tsensor.cbfn(diag->tsensor.cbarg, diag->tsensor.status);
diag->tsensor.lock = 0;
}
/*
* LED Test command
*/
static void
diag_ledtest_send(struct bfa_diag_s *diag, struct bfa_diag_ledtest_s *ledtest)
{
struct bfi_diag_ledtest_req_s *msg;
msg = (struct bfi_diag_ledtest_req_s *)diag->ledtest.mbcmd.msg;
/* build host command */
bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_LEDTEST,
bfa_ioc_portid(diag->ioc));
/*
* convert the freq from N blinks per 10 sec to
* crossbow ontime value. We do it here because division is need
*/
if (ledtest->freq)
ledtest->freq = 500 / ledtest->freq;
if (ledtest->freq == 0)
ledtest->freq = 1;
bfa_trc(diag, ledtest->freq);
/* mcpy(&ledtest_req->req, ledtest, sizeof(bfa_diag_ledtest_t)); */
msg->cmd = (u8) ledtest->cmd;
msg->color = (u8) ledtest->color;
msg->portid = bfa_ioc_portid(diag->ioc);
msg->led = ledtest->led;
msg->freq = cpu_to_be16(ledtest->freq);
/* send mbox cmd */
bfa_ioc_mbox_queue(diag->ioc, &diag->ledtest.mbcmd);
}
static void
diag_ledtest_comp(struct bfa_diag_s *diag, struct bfi_diag_ledtest_rsp_s * msg)
{
bfa_trc(diag, diag->ledtest.lock);
diag->ledtest.lock = BFA_FALSE;
/* no bfa_cb_queue is needed because driver is not waiting */
}
/*
* Port beaconing
*/
static void
diag_portbeacon_send(struct bfa_diag_s *diag, bfa_boolean_t beacon, u32 sec)
{
struct bfi_diag_portbeacon_req_s *msg;
msg = (struct bfi_diag_portbeacon_req_s *)diag->beacon.mbcmd.msg;
/* build host command */
bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_PORTBEACON,
bfa_ioc_portid(diag->ioc));
msg->beacon = beacon;
msg->period = cpu_to_be32(sec);
/* send mbox cmd */
bfa_ioc_mbox_queue(diag->ioc, &diag->beacon.mbcmd);
}
static void
diag_portbeacon_comp(struct bfa_diag_s *diag)
{
bfa_trc(diag, diag->beacon.state);
diag->beacon.state = BFA_FALSE;
if (diag->cbfn_beacon)
diag->cbfn_beacon(diag->dev, BFA_FALSE, diag->beacon.link_e2e);
}
/*
* Diag hmbox handler
*/
void
bfa_diag_intr(void *diagarg, struct bfi_mbmsg_s *msg)
{
struct bfa_diag_s *diag = diagarg;
switch (msg->mh.msg_id) {
case BFI_DIAG_I2H_PORTBEACON:
diag_portbeacon_comp(diag);
break;
case BFI_DIAG_I2H_FWPING:
diag_fwping_comp(diag, (struct bfi_diag_fwping_rsp_s *) msg);
break;
case BFI_DIAG_I2H_TEMPSENSOR:
diag_tempsensor_comp(diag, (bfi_diag_ts_rsp_t *) msg);
break;
case BFI_DIAG_I2H_LEDTEST:
diag_ledtest_comp(diag, (struct bfi_diag_ledtest_rsp_s *) msg);
break;
default:
bfa_trc(diag, msg->mh.msg_id);
WARN_ON(1);
}
}
/*
* Gen RAM Test
*
* @param[in] *diag - diag data struct
* @param[in] *memtest - mem test params input from upper layer,
* @param[in] pattern - mem test pattern
* @param[in] *result - mem test result
* @param[in] cbfn - mem test callback functioin
* @param[in] cbarg - callback functioin arg
*
* @param[out]
*/
bfa_status_t
bfa_diag_memtest(struct bfa_diag_s *diag, struct bfa_diag_memtest_s *memtest,
u32 pattern, struct bfa_diag_memtest_result *result,
bfa_cb_diag_t cbfn, void *cbarg)
{
bfa_trc(diag, pattern);
if (!bfa_ioc_adapter_is_disabled(diag->ioc))
return BFA_STATUS_ADAPTER_ENABLED;
/* check to see if there is another destructive diag cmd running */
if (diag->block) {
bfa_trc(diag, diag->block);
return BFA_STATUS_DEVBUSY;
} else
diag->block = 1;
diag->result = result;
diag->cbfn = cbfn;
diag->cbarg = cbarg;
/* download memtest code and take LPU0 out of reset */
bfa_ioc_boot(diag->ioc, BFI_FWBOOT_TYPE_MEMTEST, BFI_FWBOOT_ENV_OS);
bfa_timer_begin(diag->ioc->timer_mod, &diag->timer,
bfa_diag_memtest_done, diag, BFA_DIAG_MEMTEST_TOV);
diag->timer_active = 1;
return BFA_STATUS_OK;
}
/*
* DIAG firmware ping command
*
* @param[in] *diag - diag data struct
* @param[in] cnt - dma loop count for testing PCIE
* @param[in] data - data pattern to pass in fw
* @param[in] *result - pt to bfa_diag_fwping_result_t data struct
* @param[in] cbfn - callback function
* @param[in] *cbarg - callback functioin arg
*
* @param[out]
*/
bfa_status_t
bfa_diag_fwping(struct bfa_diag_s *diag, u32 cnt, u32 data,
struct bfa_diag_results_fwping *result, bfa_cb_diag_t cbfn,
void *cbarg)
{
bfa_trc(diag, cnt);
bfa_trc(diag, data);
if (!bfa_ioc_is_operational(diag->ioc))
return BFA_STATUS_IOC_NON_OP;
if (bfa_asic_id_ct2(bfa_ioc_devid((diag->ioc))) &&
((diag->ioc)->clscode == BFI_PCIFN_CLASS_ETH))
return BFA_STATUS_CMD_NOTSUPP;
/* check to see if there is another destructive diag cmd running */
if (diag->block || diag->fwping.lock) {
bfa_trc(diag, diag->block);
bfa_trc(diag, diag->fwping.lock);
return BFA_STATUS_DEVBUSY;
}
/* Initialization */
diag->fwping.lock = 1;
diag->fwping.cbfn = cbfn;
diag->fwping.cbarg = cbarg;
diag->fwping.result = result;
diag->fwping.data = data;
diag->fwping.count = cnt;
/* Init test results */
diag->fwping.result->data = 0;
diag->fwping.result->status = BFA_STATUS_OK;
/* kick off the first ping */
diag_fwping_send(diag);
return BFA_STATUS_OK;
}
/*
* Read Temperature Sensor
*
* @param[in] *diag - diag data struct
* @param[in] *result - pt to bfa_diag_temp_t data struct
* @param[in] cbfn - callback function
* @param[in] *cbarg - callback functioin arg
*
* @param[out]
*/
bfa_status_t
bfa_diag_tsensor_query(struct bfa_diag_s *diag,
struct bfa_diag_results_tempsensor_s *result,
bfa_cb_diag_t cbfn, void *cbarg)
{
/* check to see if there is a destructive diag cmd running */
if (diag->block || diag->tsensor.lock) {
bfa_trc(diag, diag->block);
bfa_trc(diag, diag->tsensor.lock);
return BFA_STATUS_DEVBUSY;
}
if (!bfa_ioc_is_operational(diag->ioc))
return BFA_STATUS_IOC_NON_OP;
/* Init diag mod params */
diag->tsensor.lock = 1;
diag->tsensor.temp = result;
diag->tsensor.cbfn = cbfn;
diag->tsensor.cbarg = cbarg;
/* Send msg to fw */
diag_tempsensor_send(diag);
return BFA_STATUS_OK;
}
/*
* LED Test command
*
* @param[in] *diag - diag data struct
* @param[in] *ledtest - pt to ledtest data structure
*
* @param[out]
*/
bfa_status_t
bfa_diag_ledtest(struct bfa_diag_s *diag, struct bfa_diag_ledtest_s *ledtest)
{
bfa_trc(diag, ledtest->cmd);
if (!bfa_ioc_is_operational(diag->ioc))
return BFA_STATUS_IOC_NON_OP;
if (diag->beacon.state)
return BFA_STATUS_BEACON_ON;
if (diag->ledtest.lock)
return BFA_STATUS_LEDTEST_OP;
/* Send msg to fw */
diag->ledtest.lock = BFA_TRUE;
diag_ledtest_send(diag, ledtest);
return BFA_STATUS_OK;
}
/*
* Port beaconing command
*
* @param[in] *diag - diag data struct
* @param[in] beacon - port beaconing 1:ON 0:OFF
* @param[in] link_e2e_beacon - link beaconing 1:ON 0:OFF
* @param[in] sec - beaconing duration in seconds
*
* @param[out]
*/
bfa_status_t
bfa_diag_beacon_port(struct bfa_diag_s *diag, bfa_boolean_t beacon,
bfa_boolean_t link_e2e_beacon, uint32_t sec)
{
bfa_trc(diag, beacon);
bfa_trc(diag, link_e2e_beacon);
bfa_trc(diag, sec);
if (!bfa_ioc_is_operational(diag->ioc))
return BFA_STATUS_IOC_NON_OP;
if (diag->ledtest.lock)
return BFA_STATUS_LEDTEST_OP;
if (diag->beacon.state && beacon) /* beacon alread on */
return BFA_STATUS_BEACON_ON;
diag->beacon.state = beacon;
diag->beacon.link_e2e = link_e2e_beacon;
if (diag->cbfn_beacon)
diag->cbfn_beacon(diag->dev, beacon, link_e2e_beacon);
/* Send msg to fw */
diag_portbeacon_send(diag, beacon, sec);
return BFA_STATUS_OK;
}
/*
* Return DMA memory needed by diag module.
*/
u32
bfa_diag_meminfo(void)
{
return BFA_ROUNDUP(BFI_DIAG_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
}
/*
* Attach virtual and physical memory for Diag.
*/
void
bfa_diag_attach(struct bfa_diag_s *diag, struct bfa_ioc_s *ioc, void *dev,
bfa_cb_diag_beacon_t cbfn_beacon, struct bfa_trc_mod_s *trcmod)
{
diag->dev = dev;
diag->ioc = ioc;
diag->trcmod = trcmod;
diag->block = 0;
diag->cbfn = NULL;
diag->cbarg = NULL;
diag->result = NULL;
diag->cbfn_beacon = cbfn_beacon;
bfa_ioc_mbox_regisr(diag->ioc, BFI_MC_DIAG, bfa_diag_intr, diag);
bfa_q_qe_init(&diag->ioc_notify);
bfa_ioc_notify_init(&diag->ioc_notify, bfa_diag_notify, diag);
list_add_tail(&diag->ioc_notify.qe, &diag->ioc->notify_q);
}
void
bfa_diag_memclaim(struct bfa_diag_s *diag, u8 *dm_kva, u64 dm_pa)
{
diag->fwping.dbuf_kva = dm_kva;
diag->fwping.dbuf_pa = dm_pa;
memset(diag->fwping.dbuf_kva, 0, BFI_DIAG_DMA_BUF_SZ);
}

View File

@ -491,6 +491,147 @@ void bfa_flash_attach(struct bfa_flash_s *flash, struct bfa_ioc_s *ioc,
void bfa_flash_memclaim(struct bfa_flash_s *flash,
u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg);
/*
* DIAG module specific
*/
typedef void (*bfa_cb_diag_t) (void *cbarg, bfa_status_t status);
typedef void (*bfa_cb_diag_beacon_t) (void *dev, bfa_boolean_t beacon,
bfa_boolean_t link_e2e_beacon);
/*
* Firmware ping test results
*/
struct bfa_diag_results_fwping {
u32 data; /* store the corrupted data */
u32 status;
u32 dmastatus;
u8 rsvd[4];
};
struct bfa_diag_qtest_result_s {
u32 status;
u16 count; /* sucessful queue test count */
u8 queue;
u8 rsvd; /* 64-bit align */
};
/*
* Firmware ping test results
*/
struct bfa_diag_fwping_s {
struct bfa_diag_results_fwping *result;
bfa_cb_diag_t cbfn;
void *cbarg;
u32 data;
u8 lock;
u8 rsv[3];
u32 status;
u32 count;
struct bfa_mbox_cmd_s mbcmd;
u8 *dbuf_kva; /* dma buf virtual address */
u64 dbuf_pa; /* dma buf physical address */
};
/*
* Temperature sensor query results
*/
struct bfa_diag_results_tempsensor_s {
u32 status;
u16 temp; /* 10-bit A/D value */
u16 brd_temp; /* 9-bit board temp */
u8 ts_junc; /* show junction tempsensor */
u8 ts_brd; /* show board tempsensor */
u8 rsvd[6]; /* keep 8 bytes alignment */
};
struct bfa_diag_tsensor_s {
bfa_cb_diag_t cbfn;
void *cbarg;
struct bfa_diag_results_tempsensor_s *temp;
u8 lock;
u8 rsv[3];
u32 status;
struct bfa_mbox_cmd_s mbcmd;
};
struct bfa_diag_sfpshow_s {
struct sfp_mem_s *sfpmem;
bfa_cb_diag_t cbfn;
void *cbarg;
u8 lock;
u8 static_data;
u8 rsv[2];
u32 status;
struct bfa_mbox_cmd_s mbcmd;
u8 *dbuf_kva; /* dma buf virtual address */
u64 dbuf_pa; /* dma buf physical address */
};
struct bfa_diag_led_s {
struct bfa_mbox_cmd_s mbcmd;
bfa_boolean_t lock; /* 1: ledtest is operating */
};
struct bfa_diag_beacon_s {
struct bfa_mbox_cmd_s mbcmd;
bfa_boolean_t state; /* port beacon state */
bfa_boolean_t link_e2e; /* link beacon state */
};
struct bfa_diag_s {
void *dev;
struct bfa_ioc_s *ioc;
struct bfa_trc_mod_s *trcmod;
struct bfa_diag_fwping_s fwping;
struct bfa_diag_tsensor_s tsensor;
struct bfa_diag_sfpshow_s sfpshow;
struct bfa_diag_led_s ledtest;
struct bfa_diag_beacon_s beacon;
void *result;
struct bfa_timer_s timer;
bfa_cb_diag_beacon_t cbfn_beacon;
bfa_cb_diag_t cbfn;
void *cbarg;
u8 block;
u8 timer_active;
u8 rsvd[2];
u32 status;
struct bfa_ioc_notify_s ioc_notify;
struct bfa_mem_dma_s diag_dma;
};
#define BFA_DIAG_MOD(__bfa) (&(__bfa)->modules.diag_mod)
#define BFA_MEM_DIAG_DMA(__bfa) (&(BFA_DIAG_MOD(__bfa)->diag_dma))
u32 bfa_diag_meminfo(void);
void bfa_diag_memclaim(struct bfa_diag_s *diag, u8 *dm_kva, u64 dm_pa);
void bfa_diag_attach(struct bfa_diag_s *diag, struct bfa_ioc_s *ioc, void *dev,
bfa_cb_diag_beacon_t cbfn_beacon,
struct bfa_trc_mod_s *trcmod);
bfa_status_t bfa_diag_reg_read(struct bfa_diag_s *diag, u32 offset,
u32 len, u32 *buf, u32 force);
bfa_status_t bfa_diag_reg_write(struct bfa_diag_s *diag, u32 offset,
u32 len, u32 value, u32 force);
bfa_status_t bfa_diag_tsensor_query(struct bfa_diag_s *diag,
struct bfa_diag_results_tempsensor_s *result,
bfa_cb_diag_t cbfn, void *cbarg);
bfa_status_t bfa_diag_fwping(struct bfa_diag_s *diag, u32 cnt,
u32 pattern, struct bfa_diag_results_fwping *result,
bfa_cb_diag_t cbfn, void *cbarg);
bfa_status_t bfa_diag_sfpshow(struct bfa_diag_s *diag,
struct sfp_mem_s *sfpmem, u8 static_data,
bfa_cb_diag_t cbfn, void *cbarg);
bfa_status_t bfa_diag_memtest(struct bfa_diag_s *diag,
struct bfa_diag_memtest_s *memtest, u32 pattern,
struct bfa_diag_memtest_result *result,
bfa_cb_diag_t cbfn, void *cbarg);
bfa_status_t bfa_diag_ledtest(struct bfa_diag_s *diag,
struct bfa_diag_ledtest_s *ledtest);
bfa_status_t bfa_diag_beacon_port(struct bfa_diag_s *diag,
bfa_boolean_t beacon, bfa_boolean_t link_e2e_beacon,
u32 sec);
#define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func)
#define bfa_ioc_devid(__ioc) ((__ioc)->pcidev.device_id)
#define bfa_ioc_bar0(__ioc) ((__ioc)->pcidev.pci_bar_kva)

View File

@ -29,6 +29,7 @@
#include "bfa_port.h"
struct bfa_modules_s {
struct bfa_fcdiag_s fcdiag; /* fcdiag module */
struct bfa_fcport_s fcport; /* fc port module */
struct bfa_fcxp_mod_s fcxp_mod; /* fcxp module */
struct bfa_lps_mod_s lps_mod; /* fcxp module */
@ -41,6 +42,7 @@ struct bfa_modules_s {
struct bfa_cee_s cee; /* CEE Module */
struct bfa_sfp_s sfp; /* SFP module */
struct bfa_flash_s flash; /* flash module */
struct bfa_diag_s diag_mod; /* diagnostics module */
};
/*
@ -119,6 +121,7 @@ struct bfa_s {
};
extern bfa_boolean_t bfa_auto_recover;
extern struct bfa_module_s hal_mod_fcdiag;
extern struct bfa_module_s hal_mod_sgpg;
extern struct bfa_module_s hal_mod_fcport;
extern struct bfa_module_s hal_mod_fcxp;

View File

@ -21,6 +21,7 @@
#include "bfa_modules.h"
BFA_TRC_FILE(HAL, FCXP);
BFA_MODULE(fcdiag);
BFA_MODULE(fcxp);
BFA_MODULE(sgpg);
BFA_MODULE(lps);
@ -3872,6 +3873,22 @@ bfa_fcport_get_ratelim_speed(struct bfa_s *bfa)
}
void
bfa_fcport_beacon(void *dev, bfa_boolean_t beacon,
bfa_boolean_t link_e2e_beacon)
{
struct bfa_s *bfa = dev;
struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
bfa_trc(bfa, beacon);
bfa_trc(bfa, link_e2e_beacon);
bfa_trc(bfa, fcport->beacon);
bfa_trc(bfa, fcport->link_e2e_beacon);
fcport->beacon = beacon;
fcport->link_e2e_beacon = link_e2e_beacon;
}
bfa_boolean_t
bfa_fcport_is_linkup(struct bfa_s *bfa)
{
@ -5224,3 +5241,403 @@ bfa_uf_res_recfg(struct bfa_s *bfa, u16 num_uf_fw)
list_add_tail(qe, &mod->uf_unused_q);
}
}
/*
* BFA fcdiag module
*/
#define BFA_DIAG_QTEST_TOV 1000 /* msec */
/*
* Set port status to busy
*/
static void
bfa_fcdiag_set_busy_status(struct bfa_fcdiag_s *fcdiag)
{
struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fcdiag->bfa);
if (fcdiag->lb.lock)
fcport->diag_busy = BFA_TRUE;
else
fcport->diag_busy = BFA_FALSE;
}
static void
bfa_fcdiag_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
struct bfa_s *bfa)
{
}
static void
bfa_fcdiag_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
struct bfa_pcidev_s *pcidev)
{
struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa);
fcdiag->bfa = bfa;
fcdiag->trcmod = bfa->trcmod;
/* The common DIAG attach bfa_diag_attach() will do all memory claim */
}
static void
bfa_fcdiag_iocdisable(struct bfa_s *bfa)
{
struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa);
bfa_trc(fcdiag, fcdiag->lb.lock);
if (fcdiag->lb.lock) {
fcdiag->lb.status = BFA_STATUS_IOC_FAILURE;
fcdiag->lb.cbfn(fcdiag->lb.cbarg, fcdiag->lb.status);
fcdiag->lb.lock = 0;
bfa_fcdiag_set_busy_status(fcdiag);
}
}
static void
bfa_fcdiag_detach(struct bfa_s *bfa)
{
}
static void
bfa_fcdiag_start(struct bfa_s *bfa)
{
}
static void
bfa_fcdiag_stop(struct bfa_s *bfa)
{
}
static void
bfa_fcdiag_queuetest_timeout(void *cbarg)
{
struct bfa_fcdiag_s *fcdiag = cbarg;
struct bfa_diag_qtest_result_s *res = fcdiag->qtest.result;
bfa_trc(fcdiag, fcdiag->qtest.all);
bfa_trc(fcdiag, fcdiag->qtest.count);
fcdiag->qtest.timer_active = 0;
res->status = BFA_STATUS_ETIMER;
res->count = QTEST_CNT_DEFAULT - fcdiag->qtest.count;
if (fcdiag->qtest.all)
res->queue = fcdiag->qtest.all;
bfa_trc(fcdiag, BFA_STATUS_ETIMER);
fcdiag->qtest.status = BFA_STATUS_ETIMER;
fcdiag->qtest.cbfn(fcdiag->qtest.cbarg, fcdiag->qtest.status);
fcdiag->qtest.lock = 0;
}
static bfa_status_t
bfa_fcdiag_queuetest_send(struct bfa_fcdiag_s *fcdiag)
{
u32 i;
struct bfi_diag_qtest_req_s *req;
req = bfa_reqq_next(fcdiag->bfa, fcdiag->qtest.queue);
if (!req)
return BFA_STATUS_DEVBUSY;
/* build host command */
bfi_h2i_set(req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_QTEST,
bfa_fn_lpu(fcdiag->bfa));
for (i = 0; i < BFI_LMSG_PL_WSZ; i++)
req->data[i] = QTEST_PAT_DEFAULT;
bfa_trc(fcdiag, fcdiag->qtest.queue);
/* ring door bell */
bfa_reqq_produce(fcdiag->bfa, fcdiag->qtest.queue, req->mh);
return BFA_STATUS_OK;
}
static void
bfa_fcdiag_queuetest_comp(struct bfa_fcdiag_s *fcdiag,
bfi_diag_qtest_rsp_t *rsp)
{
struct bfa_diag_qtest_result_s *res = fcdiag->qtest.result;
bfa_status_t status = BFA_STATUS_OK;
int i;
/* Check timer, should still be active */
if (!fcdiag->qtest.timer_active) {
bfa_trc(fcdiag, fcdiag->qtest.timer_active);
return;
}
/* update count */
fcdiag->qtest.count--;
/* Check result */
for (i = 0; i < BFI_LMSG_PL_WSZ; i++) {
if (rsp->data[i] != ~(QTEST_PAT_DEFAULT)) {
res->status = BFA_STATUS_DATACORRUPTED;
break;
}
}
if (res->status == BFA_STATUS_OK) {
if (fcdiag->qtest.count > 0) {
status = bfa_fcdiag_queuetest_send(fcdiag);
if (status == BFA_STATUS_OK)
return;
else
res->status = status;
} else if (fcdiag->qtest.all > 0 &&
fcdiag->qtest.queue < (BFI_IOC_MAX_CQS - 1)) {
fcdiag->qtest.count = QTEST_CNT_DEFAULT;
fcdiag->qtest.queue++;
status = bfa_fcdiag_queuetest_send(fcdiag);
if (status == BFA_STATUS_OK)
return;
else
res->status = status;
}
}
/* Stop timer when we comp all queue */
if (fcdiag->qtest.timer_active) {
bfa_timer_stop(&fcdiag->qtest.timer);
fcdiag->qtest.timer_active = 0;
}
res->queue = fcdiag->qtest.queue;
res->count = QTEST_CNT_DEFAULT - fcdiag->qtest.count;
bfa_trc(fcdiag, res->count);
bfa_trc(fcdiag, res->status);
fcdiag->qtest.status = res->status;
fcdiag->qtest.cbfn(fcdiag->qtest.cbarg, fcdiag->qtest.status);
fcdiag->qtest.lock = 0;
}
static void
bfa_fcdiag_loopback_comp(struct bfa_fcdiag_s *fcdiag,
struct bfi_diag_lb_rsp_s *rsp)
{
struct bfa_diag_loopback_result_s *res = fcdiag->lb.result;
res->numtxmfrm = be32_to_cpu(rsp->res.numtxmfrm);
res->numosffrm = be32_to_cpu(rsp->res.numosffrm);
res->numrcvfrm = be32_to_cpu(rsp->res.numrcvfrm);
res->badfrminf = be32_to_cpu(rsp->res.badfrminf);
res->badfrmnum = be32_to_cpu(rsp->res.badfrmnum);
res->status = rsp->res.status;
fcdiag->lb.status = rsp->res.status;
bfa_trc(fcdiag, fcdiag->lb.status);
fcdiag->lb.cbfn(fcdiag->lb.cbarg, fcdiag->lb.status);
fcdiag->lb.lock = 0;
bfa_fcdiag_set_busy_status(fcdiag);
}
static bfa_status_t
bfa_fcdiag_loopback_send(struct bfa_fcdiag_s *fcdiag,
struct bfa_diag_loopback_s *loopback)
{
struct bfi_diag_lb_req_s *lb_req;
lb_req = bfa_reqq_next(fcdiag->bfa, BFA_REQQ_DIAG);
if (!lb_req)
return BFA_STATUS_DEVBUSY;
/* build host command */
bfi_h2i_set(lb_req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_LOOPBACK,
bfa_fn_lpu(fcdiag->bfa));
lb_req->lb_mode = loopback->lb_mode;
lb_req->speed = loopback->speed;
lb_req->loopcnt = loopback->loopcnt;
lb_req->pattern = loopback->pattern;
/* ring door bell */
bfa_reqq_produce(fcdiag->bfa, BFA_REQQ_DIAG, lb_req->mh);
bfa_trc(fcdiag, loopback->lb_mode);
bfa_trc(fcdiag, loopback->speed);
bfa_trc(fcdiag, loopback->loopcnt);
bfa_trc(fcdiag, loopback->pattern);
return BFA_STATUS_OK;
}
/*
* cpe/rme intr handler
*/
void
bfa_fcdiag_intr(struct bfa_s *bfa, struct bfi_msg_s *msg)
{
struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa);
switch (msg->mhdr.msg_id) {
case BFI_DIAG_I2H_LOOPBACK:
bfa_fcdiag_loopback_comp(fcdiag,
(struct bfi_diag_lb_rsp_s *) msg);
break;
case BFI_DIAG_I2H_QTEST:
bfa_fcdiag_queuetest_comp(fcdiag, (bfi_diag_qtest_rsp_t *)msg);
break;
default:
bfa_trc(fcdiag, msg->mhdr.msg_id);
WARN_ON(1);
}
}
/*
* Loopback test
*
* @param[in] *bfa - bfa data struct
* @param[in] opmode - port operation mode
* @param[in] speed - port speed
* @param[in] lpcnt - loop count
* @param[in] pat - pattern to build packet
* @param[in] *result - pt to bfa_diag_loopback_result_t data struct
* @param[in] cbfn - callback function
* @param[in] cbarg - callback functioin arg
*
* @param[out]
*/
bfa_status_t
bfa_fcdiag_loopback(struct bfa_s *bfa, enum bfa_port_opmode opmode,
enum bfa_port_speed speed, u32 lpcnt, u32 pat,
struct bfa_diag_loopback_result_s *result, bfa_cb_diag_t cbfn,
void *cbarg)
{
struct bfa_diag_loopback_s loopback;
struct bfa_port_attr_s attr;
bfa_status_t status;
struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa);
if (!bfa_iocfc_is_operational(bfa))
return BFA_STATUS_IOC_NON_OP;
/* if port is PBC disabled, return error */
if (bfa_fcport_is_pbcdisabled(bfa)) {
bfa_trc(fcdiag, BFA_STATUS_PBC);
return BFA_STATUS_PBC;
}
if (bfa_fcport_is_disabled(bfa) == BFA_FALSE) {
bfa_trc(fcdiag, opmode);
return BFA_STATUS_PORT_NOT_DISABLED;
}
/* Check if the speed is supported */
bfa_fcport_get_attr(bfa, &attr);
bfa_trc(fcdiag, attr.speed_supported);
if (speed > attr.speed_supported)
return BFA_STATUS_UNSUPP_SPEED;
/* For Mezz card, port speed entered needs to be checked */
if (bfa_mfg_is_mezz(bfa->ioc.attr->card_type)) {
if (bfa_ioc_get_type(&bfa->ioc) == BFA_IOC_TYPE_FC) {
if ((speed == BFA_PORT_SPEED_1GBPS) &&
(bfa_asic_id_ct2(bfa->ioc.pcidev.device_id)))
return BFA_STATUS_UNSUPP_SPEED;
if (!(speed == BFA_PORT_SPEED_1GBPS ||
speed == BFA_PORT_SPEED_2GBPS ||
speed == BFA_PORT_SPEED_4GBPS ||
speed == BFA_PORT_SPEED_8GBPS ||
speed == BFA_PORT_SPEED_16GBPS ||
speed == BFA_PORT_SPEED_AUTO))
return BFA_STATUS_UNSUPP_SPEED;
} else {
if (speed != BFA_PORT_SPEED_10GBPS)
return BFA_STATUS_UNSUPP_SPEED;
}
}
/* check to see if there is another destructive diag cmd running */
if (fcdiag->lb.lock) {
bfa_trc(fcdiag, fcdiag->lb.lock);
return BFA_STATUS_DEVBUSY;
}
fcdiag->lb.lock = 1;
loopback.lb_mode = opmode;
loopback.speed = speed;
loopback.loopcnt = lpcnt;
loopback.pattern = pat;
fcdiag->lb.result = result;
fcdiag->lb.cbfn = cbfn;
fcdiag->lb.cbarg = cbarg;
memset(result, 0, sizeof(struct bfa_diag_loopback_result_s));
bfa_fcdiag_set_busy_status(fcdiag);
/* Send msg to fw */
status = bfa_fcdiag_loopback_send(fcdiag, &loopback);
return status;
}
/*
* DIAG queue test command
*
* @param[in] *bfa - bfa data struct
* @param[in] force - 1: don't do ioc op checking
* @param[in] queue - queue no. to test
* @param[in] *result - pt to bfa_diag_qtest_result_t data struct
* @param[in] cbfn - callback function
* @param[in] *cbarg - callback functioin arg
*
* @param[out]
*/
bfa_status_t
bfa_fcdiag_queuetest(struct bfa_s *bfa, u32 force, u32 queue,
struct bfa_diag_qtest_result_s *result, bfa_cb_diag_t cbfn,
void *cbarg)
{
struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa);
bfa_status_t status;
bfa_trc(fcdiag, force);
bfa_trc(fcdiag, queue);
if (!force && !bfa_iocfc_is_operational(bfa))
return BFA_STATUS_IOC_NON_OP;
/* check to see if there is another destructive diag cmd running */
if (fcdiag->qtest.lock) {
bfa_trc(fcdiag, fcdiag->qtest.lock);
return BFA_STATUS_DEVBUSY;
}
/* Initialization */
fcdiag->qtest.lock = 1;
fcdiag->qtest.cbfn = cbfn;
fcdiag->qtest.cbarg = cbarg;
fcdiag->qtest.result = result;
fcdiag->qtest.count = QTEST_CNT_DEFAULT;
/* Init test results */
fcdiag->qtest.result->status = BFA_STATUS_OK;
fcdiag->qtest.result->count = 0;
/* send */
if (queue < BFI_IOC_MAX_CQS) {
fcdiag->qtest.result->queue = (u8)queue;
fcdiag->qtest.queue = (u8)queue;
fcdiag->qtest.all = 0;
} else {
fcdiag->qtest.result->queue = 0;
fcdiag->qtest.queue = 0;
fcdiag->qtest.all = 1;
}
status = bfa_fcdiag_queuetest_send(fcdiag);
/* Start a timer */
if (status == BFA_STATUS_OK) {
bfa_timer_start(bfa, &fcdiag->qtest.timer,
bfa_fcdiag_queuetest_timeout, fcdiag,
BFA_DIAG_QTEST_TOV);
fcdiag->qtest.timer_active = 1;
}
return status;
}
/*
* DIAG PLB is running
*
* @param[in] *bfa - bfa data struct
*
* @param[out]
*/
bfa_status_t
bfa_fcdiag_lb_is_running(struct bfa_s *bfa)
{
struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa);
return fcdiag->lb.lock ? BFA_STATUS_DIAG_BUSY : BFA_STATUS_OK;
}

View File

@ -548,6 +548,8 @@ enum bfa_port_speed bfa_fcport_get_ratelim_speed(struct bfa_s *bfa);
void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit, u8 bb_scn);
bfa_boolean_t bfa_fcport_is_ratelim(struct bfa_s *bfa);
void bfa_fcport_beacon(void *dev, bfa_boolean_t beacon,
bfa_boolean_t link_e2e_beacon);
bfa_boolean_t bfa_fcport_is_linkup(struct bfa_s *bfa);
bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa,
union bfa_fcport_stats_u *stats,
@ -662,4 +664,49 @@ bfa_status_t bfa_faa_disable(struct bfa_s *bfa,
bfa_status_t bfa_faa_query(struct bfa_s *bfa, struct bfa_faa_attr_s *attr,
bfa_cb_iocfc_t cbfn, void *cbarg);
/*
* FC DIAG data structure
*/
struct bfa_fcdiag_qtest_s {
struct bfa_diag_qtest_result_s *result;
bfa_cb_diag_t cbfn;
void *cbarg;
struct bfa_timer_s timer;
u32 status;
u32 count;
u8 lock;
u8 queue;
u8 all;
u8 timer_active;
};
struct bfa_fcdiag_lb_s {
bfa_cb_diag_t cbfn;
void *cbarg;
void *result;
bfa_boolean_t lock;
u32 status;
};
struct bfa_fcdiag_s {
struct bfa_s *bfa; /* Back pointer to BFA */
struct bfa_trc_mod_s *trcmod;
struct bfa_fcdiag_lb_s lb;
struct bfa_fcdiag_qtest_s qtest;
};
#define BFA_FCDIAG_MOD(__bfa) (&(__bfa)->modules.fcdiag)
void bfa_fcdiag_intr(struct bfa_s *bfa, struct bfi_msg_s *msg);
bfa_status_t bfa_fcdiag_loopback(struct bfa_s *bfa,
enum bfa_port_opmode opmode,
enum bfa_port_speed speed, u32 lpcnt, u32 pat,
struct bfa_diag_loopback_result_s *result,
bfa_cb_diag_t cbfn, void *cbarg);
bfa_status_t bfa_fcdiag_queuetest(struct bfa_s *bfa, u32 ignore,
u32 queue, struct bfa_diag_qtest_result_s *result,
bfa_cb_diag_t cbfn, void *cbarg);
bfa_status_t bfa_fcdiag_lb_is_running(struct bfa_s *bfa);
#endif /* __BFA_SVC_H__ */

View File

@ -1214,6 +1214,185 @@ out:
return 0;
}
int
bfad_iocmd_diag_temp(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_diag_get_temp_s *iocmd =
(struct bfa_bsg_diag_get_temp_s *)cmd;
struct bfad_hal_comp fcomp;
unsigned long flags;
init_completion(&fcomp.comp);
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_diag_tsensor_query(BFA_DIAG_MOD(&bfad->bfa),
&iocmd->result, bfad_hcb_comp, &fcomp);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfa_trc(bfad, iocmd->status);
if (iocmd->status != BFA_STATUS_OK)
goto out;
wait_for_completion(&fcomp.comp);
iocmd->status = fcomp.status;
out:
return 0;
}
int
bfad_iocmd_diag_memtest(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_diag_memtest_s *iocmd =
(struct bfa_bsg_diag_memtest_s *)cmd;
struct bfad_hal_comp fcomp;
unsigned long flags;
init_completion(&fcomp.comp);
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_diag_memtest(BFA_DIAG_MOD(&bfad->bfa),
&iocmd->memtest, iocmd->pat,
&iocmd->result, bfad_hcb_comp, &fcomp);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfa_trc(bfad, iocmd->status);
if (iocmd->status != BFA_STATUS_OK)
goto out;
wait_for_completion(&fcomp.comp);
iocmd->status = fcomp.status;
out:
return 0;
}
int
bfad_iocmd_diag_loopback(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_diag_loopback_s *iocmd =
(struct bfa_bsg_diag_loopback_s *)cmd;
struct bfad_hal_comp fcomp;
unsigned long flags;
init_completion(&fcomp.comp);
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_fcdiag_loopback(&bfad->bfa, iocmd->opmode,
iocmd->speed, iocmd->lpcnt, iocmd->pat,
&iocmd->result, bfad_hcb_comp, &fcomp);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfa_trc(bfad, iocmd->status);
if (iocmd->status != BFA_STATUS_OK)
goto out;
wait_for_completion(&fcomp.comp);
iocmd->status = fcomp.status;
out:
return 0;
}
int
bfad_iocmd_diag_fwping(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_diag_fwping_s *iocmd =
(struct bfa_bsg_diag_fwping_s *)cmd;
struct bfad_hal_comp fcomp;
unsigned long flags;
init_completion(&fcomp.comp);
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_diag_fwping(BFA_DIAG_MOD(&bfad->bfa), iocmd->cnt,
iocmd->pattern, &iocmd->result,
bfad_hcb_comp, &fcomp);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfa_trc(bfad, iocmd->status);
if (iocmd->status != BFA_STATUS_OK)
goto out;
bfa_trc(bfad, 0x77771);
wait_for_completion(&fcomp.comp);
iocmd->status = fcomp.status;
out:
return 0;
}
int
bfad_iocmd_diag_queuetest(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_diag_qtest_s *iocmd = (struct bfa_bsg_diag_qtest_s *)cmd;
struct bfad_hal_comp fcomp;
unsigned long flags;
init_completion(&fcomp.comp);
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_fcdiag_queuetest(&bfad->bfa, iocmd->force,
iocmd->queue, &iocmd->result,
bfad_hcb_comp, &fcomp);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
if (iocmd->status != BFA_STATUS_OK)
goto out;
wait_for_completion(&fcomp.comp);
iocmd->status = fcomp.status;
out:
return 0;
}
int
bfad_iocmd_diag_sfp(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_sfp_show_s *iocmd =
(struct bfa_bsg_sfp_show_s *)cmd;
struct bfad_hal_comp fcomp;
unsigned long flags;
init_completion(&fcomp.comp);
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_sfp_show(BFA_SFP_MOD(&bfad->bfa), &iocmd->sfp,
bfad_hcb_comp, &fcomp);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfa_trc(bfad, iocmd->status);
if (iocmd->status != BFA_STATUS_OK)
goto out;
wait_for_completion(&fcomp.comp);
iocmd->status = fcomp.status;
bfa_trc(bfad, iocmd->status);
out:
return 0;
}
int
bfad_iocmd_diag_led(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_diag_led_s *iocmd = (struct bfa_bsg_diag_led_s *)cmd;
unsigned long flags;
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_diag_ledtest(BFA_DIAG_MOD(&bfad->bfa),
&iocmd->ledtest);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
return 0;
}
int
bfad_iocmd_diag_beacon_lport(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_diag_beacon_s *iocmd =
(struct bfa_bsg_diag_beacon_s *)cmd;
unsigned long flags;
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_diag_beacon_port(BFA_DIAG_MOD(&bfad->bfa),
iocmd->beacon, iocmd->link_e2e_beacon,
iocmd->second);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
return 0;
}
int
bfad_iocmd_diag_lb_stat(struct bfad_s *bfad, void *cmd)
{
struct bfa_bsg_diag_lb_stat_s *iocmd =
(struct bfa_bsg_diag_lb_stat_s *)cmd;
unsigned long flags;
spin_lock_irqsave(&bfad->bfad_lock, flags);
iocmd->status = bfa_fcdiag_lb_is_running(&bfad->bfa);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfa_trc(bfad, iocmd->status);
return 0;
}
static int
bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
unsigned int payload_len)
@ -1360,6 +1539,33 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
case IOCMD_FLASH_READ_PART:
rc = bfad_iocmd_flash_read_part(bfad, iocmd, payload_len);
break;
case IOCMD_DIAG_TEMP:
rc = bfad_iocmd_diag_temp(bfad, iocmd);
break;
case IOCMD_DIAG_MEMTEST:
rc = bfad_iocmd_diag_memtest(bfad, iocmd);
break;
case IOCMD_DIAG_LOOPBACK:
rc = bfad_iocmd_diag_loopback(bfad, iocmd);
break;
case IOCMD_DIAG_FWPING:
rc = bfad_iocmd_diag_fwping(bfad, iocmd);
break;
case IOCMD_DIAG_QUEUETEST:
rc = bfad_iocmd_diag_queuetest(bfad, iocmd);
break;
case IOCMD_DIAG_SFP:
rc = bfad_iocmd_diag_sfp(bfad, iocmd);
break;
case IOCMD_DIAG_LED:
rc = bfad_iocmd_diag_led(bfad, iocmd);
break;
case IOCMD_DIAG_BEACON_LPORT:
rc = bfad_iocmd_diag_beacon_lport(bfad, iocmd);
break;
case IOCMD_DIAG_LB_STAT:
rc = bfad_iocmd_diag_lb_stat(bfad, iocmd);
break;
default:
rc = EINVAL;
break;

View File

@ -71,6 +71,15 @@ enum {
IOCMD_FLASH_ERASE_PART,
IOCMD_FLASH_UPDATE_PART,
IOCMD_FLASH_READ_PART,
IOCMD_DIAG_TEMP,
IOCMD_DIAG_MEMTEST,
IOCMD_DIAG_LOOPBACK,
IOCMD_DIAG_FWPING,
IOCMD_DIAG_QUEUETEST,
IOCMD_DIAG_SFP,
IOCMD_DIAG_LED,
IOCMD_DIAG_BEACON_LPORT,
IOCMD_DIAG_LB_STAT,
};
struct bfa_bsg_gen_s {
@ -357,6 +366,80 @@ struct bfa_bsg_flash_s {
u64 buf_ptr;
};
struct bfa_bsg_diag_get_temp_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd;
struct bfa_diag_results_tempsensor_s result;
};
struct bfa_bsg_diag_memtest_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd[3];
u32 pat;
struct bfa_diag_memtest_result result;
struct bfa_diag_memtest_s memtest;
};
struct bfa_bsg_diag_loopback_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd;
enum bfa_port_opmode opmode;
enum bfa_port_speed speed;
u32 lpcnt;
u32 pat;
struct bfa_diag_loopback_result_s result;
};
struct bfa_bsg_diag_fwping_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd;
u32 cnt;
u32 pattern;
struct bfa_diag_results_fwping result;
};
struct bfa_bsg_diag_qtest_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd;
u32 force;
u32 queue;
struct bfa_diag_qtest_result_s result;
};
struct bfa_bsg_sfp_show_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd;
struct sfp_mem_s sfp;
};
struct bfa_bsg_diag_led_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd;
struct bfa_diag_ledtest_s ledtest;
};
struct bfa_bsg_diag_beacon_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd;
bfa_boolean_t beacon;
bfa_boolean_t link_e2e_beacon;
u32 second;
};
struct bfa_bsg_diag_lb_stat_s {
bfa_status_t status;
u16 bfad_num;
u16 rsvd;
};
struct bfa_bsg_fcpt_s {
bfa_status_t status;
u16 vf_id;

View File

@ -214,10 +214,10 @@ bfad_debugfs_read(struct file *file, char __user *buf,
#define BFA_REG_CT_ADDRSZ (0x40000)
#define BFA_REG_CB_ADDRSZ (0x20000)
#define BFA_REG_ADDRSZ(__bfa) \
((bfa_ioc_devid(&(__bfa)->ioc) == BFA_PCI_DEVICE_ID_CT) ? \
BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ)
#define BFA_REG_ADDRMSK(__bfa) ((u32)(BFA_REG_ADDRSZ(__bfa) - 1))
#define BFA_REG_ADDRSZ(__ioc) \
((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \
BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ))
#define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1)
static bfa_status_t
bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len)
@ -236,7 +236,7 @@ bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len)
return BFA_STATUS_EINVAL;
} else {
/* CB register space 64KB */
if ((offset + (len<<2)) > BFA_REG_ADDRMSK(bfa))
if ((offset + (len<<2)) > BFA_REG_ADDRMSK(&bfa->ioc))
return BFA_STATUS_EINVAL;
}
return BFA_STATUS_OK;
@ -317,7 +317,7 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
bfad->reglen = len << 2;
rb = bfa_ioc_bar0(ioc);
addr &= BFA_REG_ADDRMSK(bfa);
addr &= BFA_REG_ADDRMSK(ioc);
/* offset and len sanity check */
rc = bfad_reg_offset_check(bfa, addr, len);
@ -380,7 +380,7 @@ bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
}
kfree(kern_buf);
addr &= BFA_REG_ADDRMSK(bfa); /* offset only 17 bit and word align */
addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */
/* offset and len sanity check */
rc = bfad_reg_offset_check(bfa, addr, 1);

View File

@ -190,6 +190,7 @@ enum bfi_pcifn_class {
*/
enum bfi_mclass {
BFI_MC_IOC = 1, /* IO Controller (IOC) */
BFI_MC_DIAG = 2, /* Diagnostic Msgs */
BFI_MC_FLASH = 3, /* Flash message class */
BFI_MC_CEE = 4, /* CEE */
BFI_MC_FCPORT = 5, /* FC port */
@ -339,7 +340,7 @@ struct bfi_ioc_image_hdr_s {
((u32)(__p1_mode)))
#define BFI_FWBOOT_TYPE_NORMAL 0
#define BFI_FWBOOT_TYPE_MEMTEST 1
#define BFI_FWBOOT_TYPE_MEMTEST 2
#define BFI_FWBOOT_ENV_OS 0
enum bfi_port_mode {
@ -923,6 +924,112 @@ struct bfi_flash_erase_rsp_s {
u32 status;
};
/*
*----------------------------------------------------------------------
* DIAG
*----------------------------------------------------------------------
*/
enum bfi_diag_h2i {
BFI_DIAG_H2I_PORTBEACON = 1,
BFI_DIAG_H2I_LOOPBACK = 2,
BFI_DIAG_H2I_FWPING = 3,
BFI_DIAG_H2I_TEMPSENSOR = 4,
BFI_DIAG_H2I_LEDTEST = 5,
BFI_DIAG_H2I_QTEST = 6,
};
enum bfi_diag_i2h {
BFI_DIAG_I2H_PORTBEACON = BFA_I2HM(BFI_DIAG_H2I_PORTBEACON),
BFI_DIAG_I2H_LOOPBACK = BFA_I2HM(BFI_DIAG_H2I_LOOPBACK),
BFI_DIAG_I2H_FWPING = BFA_I2HM(BFI_DIAG_H2I_FWPING),
BFI_DIAG_I2H_TEMPSENSOR = BFA_I2HM(BFI_DIAG_H2I_TEMPSENSOR),
BFI_DIAG_I2H_LEDTEST = BFA_I2HM(BFI_DIAG_H2I_LEDTEST),
BFI_DIAG_I2H_QTEST = BFA_I2HM(BFI_DIAG_H2I_QTEST),
};
#define BFI_DIAG_MAX_SGES 2
#define BFI_DIAG_DMA_BUF_SZ (2 * 1024)
#define BFI_BOOT_MEMTEST_RES_ADDR 0x900
#define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3
struct bfi_diag_lb_req_s {
struct bfi_mhdr_s mh;
u32 loopcnt;
u32 pattern;
u8 lb_mode; /*!< bfa_port_opmode_t */
u8 speed; /*!< bfa_port_speed_t */
u8 rsvd[2];
};
struct bfi_diag_lb_rsp_s {
struct bfi_mhdr_s mh; /* 4 bytes */
struct bfa_diag_loopback_result_s res; /* 16 bytes */
};
struct bfi_diag_fwping_req_s {
struct bfi_mhdr_s mh; /* 4 bytes */
struct bfi_alen_s alen; /* 12 bytes */
u32 data; /* user input data pattern */
u32 count; /* user input dma count */
u8 qtag; /* track CPE vc */
u8 rsv[3];
};
struct bfi_diag_fwping_rsp_s {
struct bfi_mhdr_s mh; /* 4 bytes */
u32 data; /* user input data pattern */
u8 qtag; /* track CPE vc */
u8 dma_status; /* dma status */
u8 rsv[2];
};
/*
* Temperature Sensor
*/
struct bfi_diag_ts_req_s {
struct bfi_mhdr_s mh; /* 4 bytes */
u16 temp; /* 10-bit A/D value */
u16 brd_temp; /* 9-bit board temp */
u8 status;
u8 ts_junc; /* show junction tempsensor */
u8 ts_brd; /* show board tempsensor */
u8 rsv;
};
#define bfi_diag_ts_rsp_t struct bfi_diag_ts_req_s
struct bfi_diag_ledtest_req_s {
struct bfi_mhdr_s mh; /* 4 bytes */
u8 cmd;
u8 color;
u8 portid;
u8 led; /* bitmap of LEDs to be tested */
u16 freq; /* no. of blinks every 10 secs */
u8 rsv[2];
};
/* notify host led operation is done */
struct bfi_diag_ledtest_rsp_s {
struct bfi_mhdr_s mh; /* 4 bytes */
};
struct bfi_diag_portbeacon_req_s {
struct bfi_mhdr_s mh; /* 4 bytes */
u32 period; /* beaconing period */
u8 beacon; /* 1: beacon on */
u8 rsvd[3];
};
/* notify host the beacon is off */
struct bfi_diag_portbeacon_rsp_s {
struct bfi_mhdr_s mh; /* 4 bytes */
};
struct bfi_diag_qtest_req_s {
struct bfi_mhdr_s mh; /* 4 bytes */
u32 data[BFI_LMSG_PL_WSZ]; /* fill up tcm prefetch area */
};
#define bfi_diag_qtest_rsp_t struct bfi_diag_qtest_req_s
#pragma pack()
#endif /* __BFI_H__ */