scsi: elx: efct: Link and host statistics

Add routines to retrieve link stats and host stats, add firmware update
helper routines.

Link: https://lore.kernel.org/r/20210601235512.20104-28-jsmart2021@gmail.com
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Daniel Wagner <dwagner@suse.de>
Co-developed-by: Ram Vegesna <ram.vegesna@broadcom.com>
Signed-off-by: Ram Vegesna <ram.vegesna@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
James Smart 2021-06-01 16:55:08 -07:00 committed by Martin K. Petersen
parent dd53d333aa
commit 6ae7147bfe
2 changed files with 356 additions and 0 deletions

View File

@ -8,6 +8,23 @@
#include "efct_hw.h" #include "efct_hw.h"
#include "efct_unsol.h" #include "efct_unsol.h"
struct efct_hw_link_stat_cb_arg {
void (*cb)(int status, u32 num_counters,
struct efct_hw_link_stat_counts *counters, void *arg);
void *arg;
};
struct efct_hw_host_stat_cb_arg {
void (*cb)(int status, u32 num_counters,
struct efct_hw_host_stat_counts *counters, void *arg);
void *arg;
};
struct efct_hw_fw_wr_cb_arg {
void (*cb)(int status, u32 bytes_written, u32 change_status, void *arg);
void *arg;
};
struct efct_mbox_rqst_ctx { struct efct_mbox_rqst_ctx {
int (*callback)(struct efc *efc, int status, u8 *mqe, void *arg); int (*callback)(struct efc *efc, int status, u8 *mqe, void *arg);
void *arg; void *arg;
@ -3002,3 +3019,313 @@ efct_hw_send_frame(struct efct_hw *hw, struct fc_frame_header *hdr,
return 0; return 0;
} }
static int
efct_hw_cb_link_stat(struct efct_hw *hw, int status,
u8 *mqe, void *arg)
{
struct sli4_cmd_read_link_stats *mbox_rsp;
struct efct_hw_link_stat_cb_arg *cb_arg = arg;
struct efct_hw_link_stat_counts counts[EFCT_HW_LINK_STAT_MAX];
u32 num_counters, i;
u32 mbox_rsp_flags = 0;
mbox_rsp = (struct sli4_cmd_read_link_stats *)mqe;
mbox_rsp_flags = le32_to_cpu(mbox_rsp->dw1_flags);
num_counters = (mbox_rsp_flags & SLI4_READ_LNKSTAT_GEC) ? 20 : 13;
memset(counts, 0, sizeof(struct efct_hw_link_stat_counts) *
EFCT_HW_LINK_STAT_MAX);
/* Fill overflow counts, mask starts from SLI4_READ_LNKSTAT_W02OF*/
for (i = 0; i < EFCT_HW_LINK_STAT_MAX; i++)
counts[i].overflow = (mbox_rsp_flags & (1 << (i + 2)));
counts[EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT].counter =
le32_to_cpu(mbox_rsp->linkfail_errcnt);
counts[EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter =
le32_to_cpu(mbox_rsp->losssync_errcnt);
counts[EFCT_HW_LINK_STAT_LOSS_OF_SIGNAL_COUNT].counter =
le32_to_cpu(mbox_rsp->losssignal_errcnt);
counts[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter =
le32_to_cpu(mbox_rsp->primseq_errcnt);
counts[EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter =
le32_to_cpu(mbox_rsp->inval_txword_errcnt);
counts[EFCT_HW_LINK_STAT_CRC_COUNT].counter =
le32_to_cpu(mbox_rsp->crc_errcnt);
counts[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_TIMEOUT_COUNT].counter =
le32_to_cpu(mbox_rsp->primseq_eventtimeout_cnt);
counts[EFCT_HW_LINK_STAT_ELASTIC_BUFFER_OVERRUN_COUNT].counter =
le32_to_cpu(mbox_rsp->elastic_bufoverrun_errcnt);
counts[EFCT_HW_LINK_STAT_ARB_TIMEOUT_COUNT].counter =
le32_to_cpu(mbox_rsp->arbit_fc_al_timeout_cnt);
counts[EFCT_HW_LINK_STAT_ADVERTISED_RCV_B2B_CREDIT].counter =
le32_to_cpu(mbox_rsp->adv_rx_buftor_to_buf_credit);
counts[EFCT_HW_LINK_STAT_CURR_RCV_B2B_CREDIT].counter =
le32_to_cpu(mbox_rsp->curr_rx_buf_to_buf_credit);
counts[EFCT_HW_LINK_STAT_ADVERTISED_XMIT_B2B_CREDIT].counter =
le32_to_cpu(mbox_rsp->adv_tx_buf_to_buf_credit);
counts[EFCT_HW_LINK_STAT_CURR_XMIT_B2B_CREDIT].counter =
le32_to_cpu(mbox_rsp->curr_tx_buf_to_buf_credit);
counts[EFCT_HW_LINK_STAT_RCV_EOFA_COUNT].counter =
le32_to_cpu(mbox_rsp->rx_eofa_cnt);
counts[EFCT_HW_LINK_STAT_RCV_EOFDTI_COUNT].counter =
le32_to_cpu(mbox_rsp->rx_eofdti_cnt);
counts[EFCT_HW_LINK_STAT_RCV_EOFNI_COUNT].counter =
le32_to_cpu(mbox_rsp->rx_eofni_cnt);
counts[EFCT_HW_LINK_STAT_RCV_SOFF_COUNT].counter =
le32_to_cpu(mbox_rsp->rx_soff_cnt);
counts[EFCT_HW_LINK_STAT_RCV_DROPPED_NO_AER_COUNT].counter =
le32_to_cpu(mbox_rsp->rx_dropped_no_aer_cnt);
counts[EFCT_HW_LINK_STAT_RCV_DROPPED_NO_RPI_COUNT].counter =
le32_to_cpu(mbox_rsp->rx_dropped_no_avail_rpi_rescnt);
counts[EFCT_HW_LINK_STAT_RCV_DROPPED_NO_XRI_COUNT].counter =
le32_to_cpu(mbox_rsp->rx_dropped_no_avail_xri_rescnt);
if (cb_arg) {
if (cb_arg->cb) {
if (status == 0 && le16_to_cpu(mbox_rsp->hdr.status))
status = le16_to_cpu(mbox_rsp->hdr.status);
cb_arg->cb(status, num_counters, counts, cb_arg->arg);
}
kfree(cb_arg);
}
return 0;
}
int
efct_hw_get_link_stats(struct efct_hw *hw, u8 req_ext_counters,
u8 clear_overflow_flags, u8 clear_all_counters,
void (*cb)(int status, u32 num_counters,
struct efct_hw_link_stat_counts *counters,
void *arg),
void *arg)
{
int rc = -EIO;
struct efct_hw_link_stat_cb_arg *cb_arg;
u8 mbxdata[SLI4_BMBX_SIZE];
cb_arg = kzalloc(sizeof(*cb_arg), GFP_ATOMIC);
if (!cb_arg)
return -ENOMEM;
cb_arg->cb = cb;
cb_arg->arg = arg;
/* Send the HW command */
if (!sli_cmd_read_link_stats(&hw->sli, mbxdata, req_ext_counters,
clear_overflow_flags, clear_all_counters))
rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
efct_hw_cb_link_stat, cb_arg);
if (rc)
kfree(cb_arg);
return rc;
}
static int
efct_hw_cb_host_stat(struct efct_hw *hw, int status, u8 *mqe, void *arg)
{
struct sli4_cmd_read_status *mbox_rsp =
(struct sli4_cmd_read_status *)mqe;
struct efct_hw_host_stat_cb_arg *cb_arg = arg;
struct efct_hw_host_stat_counts counts[EFCT_HW_HOST_STAT_MAX];
u32 num_counters = EFCT_HW_HOST_STAT_MAX;
memset(counts, 0, sizeof(struct efct_hw_host_stat_counts) *
EFCT_HW_HOST_STAT_MAX);
counts[EFCT_HW_HOST_STAT_TX_KBYTE_COUNT].counter =
le32_to_cpu(mbox_rsp->trans_kbyte_cnt);
counts[EFCT_HW_HOST_STAT_RX_KBYTE_COUNT].counter =
le32_to_cpu(mbox_rsp->recv_kbyte_cnt);
counts[EFCT_HW_HOST_STAT_TX_FRAME_COUNT].counter =
le32_to_cpu(mbox_rsp->trans_frame_cnt);
counts[EFCT_HW_HOST_STAT_RX_FRAME_COUNT].counter =
le32_to_cpu(mbox_rsp->recv_frame_cnt);
counts[EFCT_HW_HOST_STAT_TX_SEQ_COUNT].counter =
le32_to_cpu(mbox_rsp->trans_seq_cnt);
counts[EFCT_HW_HOST_STAT_RX_SEQ_COUNT].counter =
le32_to_cpu(mbox_rsp->recv_seq_cnt);
counts[EFCT_HW_HOST_STAT_TOTAL_EXCH_ORIG].counter =
le32_to_cpu(mbox_rsp->tot_exchanges_orig);
counts[EFCT_HW_HOST_STAT_TOTAL_EXCH_RESP].counter =
le32_to_cpu(mbox_rsp->tot_exchanges_resp);
counts[EFCT_HW_HOSY_STAT_RX_P_BSY_COUNT].counter =
le32_to_cpu(mbox_rsp->recv_p_bsy_cnt);
counts[EFCT_HW_HOST_STAT_RX_F_BSY_COUNT].counter =
le32_to_cpu(mbox_rsp->recv_f_bsy_cnt);
counts[EFCT_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_RQ_BUF_COUNT].counter =
le32_to_cpu(mbox_rsp->no_rq_buf_dropped_frames_cnt);
counts[EFCT_HW_HOST_STAT_EMPTY_RQ_TIMEOUT_COUNT].counter =
le32_to_cpu(mbox_rsp->empty_rq_timeout_cnt);
counts[EFCT_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_XRI_COUNT].counter =
le32_to_cpu(mbox_rsp->no_xri_dropped_frames_cnt);
counts[EFCT_HW_HOST_STAT_EMPTY_XRI_POOL_COUNT].counter =
le32_to_cpu(mbox_rsp->empty_xri_pool_cnt);
if (cb_arg) {
if (cb_arg->cb) {
if (status == 0 && le16_to_cpu(mbox_rsp->hdr.status))
status = le16_to_cpu(mbox_rsp->hdr.status);
cb_arg->cb(status, num_counters, counts, cb_arg->arg);
}
kfree(cb_arg);
}
return 0;
}
int
efct_hw_get_host_stats(struct efct_hw *hw, u8 cc,
void (*cb)(int status, u32 num_counters,
struct efct_hw_host_stat_counts *counters,
void *arg),
void *arg)
{
int rc = -EIO;
struct efct_hw_host_stat_cb_arg *cb_arg;
u8 mbxdata[SLI4_BMBX_SIZE];
cb_arg = kmalloc(sizeof(*cb_arg), GFP_ATOMIC);
if (!cb_arg)
return -ENOMEM;
cb_arg->cb = cb;
cb_arg->arg = arg;
/* Send the HW command to get the host stats */
if (!sli_cmd_read_status(&hw->sli, mbxdata, cc))
rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
efct_hw_cb_host_stat, cb_arg);
if (rc) {
efc_log_debug(hw->os, "READ_HOST_STATS failed\n");
kfree(cb_arg);
}
return rc;
}
struct efct_hw_async_call_ctx {
efct_hw_async_cb_t callback;
void *arg;
u8 cmd[SLI4_BMBX_SIZE];
};
static void
efct_hw_async_cb(struct efct_hw *hw, int status, u8 *mqe, void *arg)
{
struct efct_hw_async_call_ctx *ctx = arg;
if (ctx) {
if (ctx->callback)
(*ctx->callback)(hw, status, mqe, ctx->arg);
kfree(ctx);
}
}
int
efct_hw_async_call(struct efct_hw *hw, efct_hw_async_cb_t callback, void *arg)
{
struct efct_hw_async_call_ctx *ctx;
int rc;
/*
* Allocate a callback context (which includes the mbox cmd buffer),
* we need this to be persistent as the mbox cmd submission may be
* queued and executed later execution.
*/
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->callback = callback;
ctx->arg = arg;
/* Build and send a NOP mailbox command */
if (sli_cmd_common_nop(&hw->sli, ctx->cmd, 0)) {
efc_log_err(hw->os, "COMMON_NOP format failure\n");
kfree(ctx);
return -EIO;
}
rc = efct_hw_command(hw, ctx->cmd, EFCT_CMD_NOWAIT, efct_hw_async_cb,
ctx);
if (rc) {
efc_log_err(hw->os, "COMMON_NOP command failure, rc=%d\n", rc);
kfree(ctx);
return -EIO;
}
return 0;
}
static int
efct_hw_cb_fw_write(struct efct_hw *hw, int status, u8 *mqe, void *arg)
{
struct sli4_cmd_sli_config *mbox_rsp =
(struct sli4_cmd_sli_config *)mqe;
struct sli4_rsp_cmn_write_object *wr_obj_rsp;
struct efct_hw_fw_wr_cb_arg *cb_arg = arg;
u32 bytes_written;
u16 mbox_status;
u32 change_status;
wr_obj_rsp = (struct sli4_rsp_cmn_write_object *)
&mbox_rsp->payload.embed;
bytes_written = le32_to_cpu(wr_obj_rsp->actual_write_length);
mbox_status = le16_to_cpu(mbox_rsp->hdr.status);
change_status = (le32_to_cpu(wr_obj_rsp->change_status_dword) &
RSP_CHANGE_STATUS);
if (cb_arg) {
if (cb_arg->cb) {
if (!status && mbox_status)
status = mbox_status;
cb_arg->cb(status, bytes_written, change_status,
cb_arg->arg);
}
kfree(cb_arg);
}
return 0;
}
int
efct_hw_firmware_write(struct efct_hw *hw, struct efc_dma *dma, u32 size,
u32 offset, int last,
void (*cb)(int status, u32 bytes_written,
u32 change_status, void *arg),
void *arg)
{
int rc = -EIO;
u8 mbxdata[SLI4_BMBX_SIZE];
struct efct_hw_fw_wr_cb_arg *cb_arg;
int noc = 0;
cb_arg = kzalloc(sizeof(*cb_arg), GFP_KERNEL);
if (!cb_arg)
return -ENOMEM;
cb_arg->cb = cb;
cb_arg->arg = arg;
/* Write a portion of a firmware image to the device */
if (!sli_cmd_common_write_object(&hw->sli, mbxdata,
noc, last, size, offset, "/prg/",
dma))
rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
efct_hw_cb_fw_write, cb_arg);
if (rc != 0) {
efc_log_debug(hw->os, "COMMON_WRITE_OBJECT failed\n");
kfree(cb_arg);
}
return rc;
}

View File

@ -705,4 +705,33 @@ int
efct_hw_bls_send(struct efct *efct, u32 type, struct sli_bls_params *bls_params, efct_hw_bls_send(struct efct *efct, u32 type, struct sli_bls_params *bls_params,
void *cb, void *arg); void *cb, void *arg);
/* Function for retrieving link statistics */
int
efct_hw_get_link_stats(struct efct_hw *hw,
u8 req_ext_counters,
u8 clear_overflow_flags,
u8 clear_all_counters,
void (*efct_hw_link_stat_cb_t)(int status,
u32 num_counters,
struct efct_hw_link_stat_counts *counters, void *arg),
void *arg);
/* Function for retrieving host statistics */
int
efct_hw_get_host_stats(struct efct_hw *hw,
u8 cc,
void (*efct_hw_host_stat_cb_t)(int status,
u32 num_counters,
struct efct_hw_host_stat_counts *counters, void *arg),
void *arg);
int
efct_hw_firmware_write(struct efct_hw *hw, struct efc_dma *dma,
u32 size, u32 offset, int last,
void (*cb)(int status, u32 bytes_written,
u32 change_status, void *arg),
void *arg);
typedef void (*efct_hw_async_cb_t)(struct efct_hw *hw, int status,
u8 *mqe, void *arg);
int
efct_hw_async_call(struct efct_hw *hw, efct_hw_async_cb_t callback, void *arg);
#endif /* __EFCT_H__ */ #endif /* __EFCT_H__ */