Added support driver state capture/retrieval

MFC after:5 days
This commit is contained in:
David C Somayajulu 2017-10-11 20:22:01 +00:00
parent d7d2f0d4d1
commit ab142b3f49
7 changed files with 310 additions and 2 deletions

View File

@ -201,7 +201,6 @@ struct qla_host {
qla_rx_buf_t *rxb_free;
uint32_t rxb_free_count;
volatile uint32_t posting;
/* stats */
uint32_t err_m_getcl;

View File

@ -112,4 +112,8 @@ extern unsigned int ql83xx_resetseq_len;
extern unsigned char ql83xx_minidump[];
extern unsigned int ql83xx_minidump_len;
extern void ql_alloc_drvr_state_buffer(qla_host_t *ha);
extern void ql_free_drvr_state_buffer(qla_host_t *ha);
extern void ql_capture_drvr_state(qla_host_t *ha);
#endif /* #ifndef_QL_GLBL_H_ */

View File

@ -1703,6 +1703,9 @@ typedef struct _qla_hw {
uint32_t mdump_buffer_size;
void *mdump_template;
uint32_t mdump_template_size;
/* driver state related */
void *drvr_state;
} qla_hw_t;
#define QL_UPDATE_RDS_PRODUCER_INDEX(ha, prod_reg, val) \

View File

@ -39,7 +39,11 @@ __FBSDID("$FreeBSD$");
#include "ql_inline.h"
#include "ql_glbl.h"
#include "ql_ioctl.h"
#include "ql_ver.h"
#include "ql_dbg.h"
static int ql_drvr_state(qla_host_t *ha, qla_driver_state_t *drvr_state);
static uint32_t ql_drvr_state_size(qla_host_t *ha);
static int ql_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
struct thread *td);
@ -279,6 +283,10 @@ ql_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
rval = ENXIO;
break;
case QLA_RD_DRVR_STATE:
rval = ql_drvr_state(ha, (qla_driver_state_t *)data);
break;
case QLA_RD_PCI_IDS:
pci_ids = (qla_rd_pci_ids_t *)data;
pci_ids->ven_id = pci_get_vendor(pci_dev);
@ -295,3 +303,223 @@ ql_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
return rval;
}
static int
ql_drvr_state(qla_host_t *ha, qla_driver_state_t *state)
{
int rval = 0;
uint32_t drvr_state_size;
qla_drvr_state_hdr_t *hdr;
drvr_state_size = ql_drvr_state_size(ha);
if (state->buffer == NULL) {
state->size = drvr_state_size;
return (0);
}
if (state->size < drvr_state_size)
return (ENXIO);
if (ha->hw.drvr_state == NULL)
return (ENOMEM);
hdr = ha->hw.drvr_state;
if (!hdr->drvr_version_major)
ql_capture_drvr_state(ha);
rval = copyout(ha->hw.drvr_state, state->buffer, drvr_state_size);
bzero(ha->hw.drvr_state, drvr_state_size);
return (rval);
}
static uint32_t
ql_drvr_state_size(qla_host_t *ha)
{
uint32_t drvr_state_size;
uint32_t size;
size = sizeof (qla_drvr_state_hdr_t);
drvr_state_size = QL_ALIGN(size, 64);
size = ha->hw.num_tx_rings * (sizeof (qla_drvr_state_tx_t));
drvr_state_size += QL_ALIGN(size, 64);
size = ha->hw.num_rds_rings * (sizeof (qla_drvr_state_rx_t));
drvr_state_size += QL_ALIGN(size, 64);
size = ha->hw.num_sds_rings * (sizeof (qla_drvr_state_sds_t));
drvr_state_size += QL_ALIGN(size, 64);
size = sizeof(q80_tx_cmd_t) * NUM_TX_DESCRIPTORS * ha->hw.num_tx_rings;
drvr_state_size += QL_ALIGN(size, 64);
size = sizeof(q80_recv_desc_t) * NUM_RX_DESCRIPTORS * ha->hw.num_rds_rings;
drvr_state_size += QL_ALIGN(size, 64);
size = sizeof(q80_stat_desc_t) * NUM_STATUS_DESCRIPTORS *
ha->hw.num_sds_rings;
drvr_state_size += QL_ALIGN(size, 64);
return (drvr_state_size);
}
static void
ql_get_tx_state(qla_host_t *ha, qla_drvr_state_tx_t *tx_state)
{
int i;
for (i = 0; i < ha->hw.num_tx_rings; i++) {
tx_state->base_p_addr = ha->hw.tx_cntxt[i].tx_ring_paddr;
tx_state->cons_p_addr = ha->hw.tx_cntxt[i].tx_cons_paddr;
tx_state->tx_prod_reg = ha->hw.tx_cntxt[i].tx_prod_reg;
tx_state->tx_cntxt_id = ha->hw.tx_cntxt[i].tx_cntxt_id;
tx_state->txr_free = ha->hw.tx_cntxt[i].txr_free;
tx_state->txr_next = ha->hw.tx_cntxt[i].txr_next;
tx_state->txr_comp = ha->hw.tx_cntxt[i].txr_comp;
tx_state++;
}
return;
}
static void
ql_get_rx_state(qla_host_t *ha, qla_drvr_state_rx_t *rx_state)
{
int i;
for (i = 0; i < ha->hw.num_rds_rings; i++) {
rx_state->prod_std = ha->hw.rds[i].prod_std;
rx_state->rx_next = ha->hw.rds[i].rx_next;
rx_state++;
}
return;
}
static void
ql_get_sds_state(qla_host_t *ha, qla_drvr_state_sds_t *sds_state)
{
int i;
for (i = 0; i < ha->hw.num_sds_rings; i++) {
sds_state->sdsr_next = ha->hw.sds[i].sdsr_next;
sds_state->sds_consumer = ha->hw.sds[i].sds_consumer;
sds_state++;
}
return;
}
void
ql_capture_drvr_state(qla_host_t *ha)
{
uint8_t *state_buffer;
uint8_t *ptr;
uint32_t drvr_state_size;
qla_drvr_state_hdr_t *hdr;
uint32_t size;
int i;
drvr_state_size = ql_drvr_state_size(ha);
state_buffer = ha->hw.drvr_state;
if (state_buffer == NULL)
return;
bzero(state_buffer, drvr_state_size);
hdr = (qla_drvr_state_hdr_t *)state_buffer;
hdr->drvr_version_major = QLA_VERSION_MAJOR;
hdr->drvr_version_minor = QLA_VERSION_MINOR;
hdr->drvr_version_build = QLA_VERSION_BUILD;
bcopy(ha->hw.mac_addr, hdr->mac_addr, ETHER_ADDR_LEN);
hdr->link_speed = ha->hw.link_speed;
hdr->cable_length = ha->hw.cable_length;
hdr->cable_oui = ha->hw.cable_oui;
hdr->link_up = ha->hw.link_up;
hdr->module_type = ha->hw.module_type;
hdr->link_faults = ha->hw.link_faults;
hdr->rcv_intr_coalesce = ha->hw.rcv_intr_coalesce;
hdr->xmt_intr_coalesce = ha->hw.xmt_intr_coalesce;
size = sizeof (qla_drvr_state_hdr_t);
hdr->tx_state_offset = QL_ALIGN(size, 64);
ptr = state_buffer + hdr->tx_state_offset;
ql_get_tx_state(ha, (qla_drvr_state_tx_t *)ptr);
size = ha->hw.num_tx_rings * (sizeof (qla_drvr_state_tx_t));
hdr->rx_state_offset = hdr->tx_state_offset + QL_ALIGN(size, 64);
ptr = state_buffer + hdr->rx_state_offset;
ql_get_rx_state(ha, (qla_drvr_state_rx_t *)ptr);
size = ha->hw.num_rds_rings * (sizeof (qla_drvr_state_rx_t));
hdr->sds_state_offset = hdr->rx_state_offset + QL_ALIGN(size, 64);
ptr = state_buffer + hdr->sds_state_offset;
ql_get_sds_state(ha, (qla_drvr_state_sds_t *)ptr);
size = ha->hw.num_sds_rings * (sizeof (qla_drvr_state_sds_t));
hdr->txr_offset = hdr->sds_state_offset + QL_ALIGN(size, 64);
ptr = state_buffer + hdr->txr_offset;
hdr->num_tx_rings = ha->hw.num_tx_rings;
hdr->txr_size = sizeof(q80_tx_cmd_t) * NUM_TX_DESCRIPTORS;
hdr->txr_entries = NUM_TX_DESCRIPTORS;
size = hdr->num_tx_rings * hdr->txr_size;
bcopy(ha->hw.dma_buf.tx_ring.dma_b, ptr, size);
hdr->rxr_offset = hdr->txr_offset + QL_ALIGN(size, 64);
ptr = state_buffer + hdr->rxr_offset;
hdr->rxr_size = sizeof(q80_recv_desc_t) * NUM_RX_DESCRIPTORS;
hdr->rxr_entries = NUM_RX_DESCRIPTORS;
hdr->num_rx_rings = ha->hw.num_rds_rings;
for (i = 0; i < ha->hw.num_rds_rings; i++) {
bcopy(ha->hw.dma_buf.rds_ring[i].dma_b, ptr, hdr->rxr_size);
ptr += hdr->rxr_size;
}
size = hdr->rxr_size * hdr->num_rx_rings;
hdr->sds_offset = hdr->rxr_offset + QL_ALIGN(size, 64);
hdr->sds_ring_size = sizeof(q80_stat_desc_t) * NUM_STATUS_DESCRIPTORS;
hdr->sds_entries = NUM_STATUS_DESCRIPTORS;
hdr->num_sds_rings = ha->hw.num_sds_rings;
ptr = state_buffer + hdr->sds_offset;
for (i = 0; i < ha->hw.num_sds_rings; i++) {
bcopy(ha->hw.dma_buf.sds_ring[i].dma_b, ptr, hdr->sds_ring_size);
ptr += hdr->sds_ring_size;
}
return;
}
void
ql_alloc_drvr_state_buffer(qla_host_t *ha)
{
uint32_t drvr_state_size;
drvr_state_size = ql_drvr_state_size(ha);
ha->hw.drvr_state = malloc(drvr_state_size, M_QLA83XXBUF, M_NOWAIT);
return;
}
void
ql_free_drvr_state_buffer(qla_host_t *ha)
{
if (ha->hw.drvr_state != NULL)
free(ha->hw.drvr_state, M_QLA83XXBUF);
return;
}

View File

@ -93,6 +93,72 @@ struct qla_rd_fw_dump {
};
typedef struct qla_rd_fw_dump qla_rd_fw_dump_t;
struct qla_drvr_state_tx {
uint64_t base_p_addr;
uint64_t cons_p_addr;
uint32_t tx_prod_reg;
uint32_t tx_cntxt_id;
uint32_t txr_free;
uint32_t txr_next;
uint32_t txr_comp;
};
typedef struct qla_drvr_state_tx qla_drvr_state_tx_t;
struct qla_drvr_state_sds {
uint32_t sdsr_next; /* next entry in SDS ring to process */
uint32_t sds_consumer;
};
typedef struct qla_drvr_state_sds qla_drvr_state_sds_t;
struct qla_drvr_state_rx {
uint32_t prod_std;
uint32_t rx_next; /* next standard rcv ring to arm fw */;
};
typedef struct qla_drvr_state_rx qla_drvr_state_rx_t;
struct qla_drvr_state_hdr {
uint32_t drvr_version_major;
uint32_t drvr_version_minor;
uint32_t drvr_version_build;
uint8_t mac_addr[ETHER_ADDR_LEN];
uint16_t link_speed;
uint16_t cable_length;
uint32_t cable_oui;
uint8_t link_up;
uint8_t module_type;
uint8_t link_faults;
uint32_t rcv_intr_coalesce;
uint32_t xmt_intr_coalesce;
uint32_t tx_state_offset;/* size = sizeof (qla_drvr_state_tx_t) * num_tx_rings */
uint32_t rx_state_offset;/* size = sizeof (qla_drvr_state_rx_t) * num_rx_rings */
uint32_t sds_state_offset;/* size = sizeof (qla_drvr_state_sds_t) * num_sds_rings */
uint32_t num_tx_rings; /* number of tx rings */
uint32_t txr_size; /* size of each tx ring in bytes */
uint32_t txr_entries; /* number of descriptors in each tx ring */
uint32_t txr_offset; /* start of tx ring [0 - #rings] content */
uint32_t num_rx_rings; /* number of rx rings */
uint32_t rxr_size; /* size of each rx ring in bytes */
uint32_t rxr_entries; /* number of descriptors in each rx ring */
uint32_t rxr_offset; /* start of rx ring [0 - #rings] content */
uint32_t num_sds_rings; /* number of sds rings */
uint32_t sds_ring_size; /* size of each sds ring in bytes */
uint32_t sds_entries; /* number of descriptors in each sds ring */
uint32_t sds_offset; /* start of sds ring [0 - #rings] content */
};
typedef struct qla_drvr_state_hdr qla_drvr_state_hdr_t;
struct qla_driver_state {
uint32_t size;
void *buffer;
};
typedef struct qla_driver_state qla_driver_state_t;
/*
* Read/Write Register
*/
@ -133,4 +199,10 @@ typedef struct qla_rd_fw_dump qla_rd_fw_dump_t;
*/
#define QLA_RD_FW_DUMP _IOWR('q', 8, qla_rd_fw_dump_t)
/*
* Read Driver State
*/
#define QLA_RD_DRVR_STATE _IOWR('q', 9, qla_driver_state_t)
#endif /* #ifndef _QL_IOCTL_H_ */

View File

@ -492,6 +492,7 @@ qla_pci_attach(device_t dev)
device_printf(dev, "%s: ql_minidump_init failed\n", __func__);
goto qla_pci_attach_err;
}
ql_alloc_drvr_state_buffer(ha);
/* create the o.s ethernet interface */
qla_init_ifnet(dev, ha);
@ -645,6 +646,7 @@ qla_release(qla_host_t *ha)
if (ha->ifp != NULL)
ether_ifdetach(ha->ifp);
ql_free_drvr_state_buffer(ha);
ql_free_dma(ha);
qla_free_parent_dma_tag(ha);

View File

@ -36,6 +36,6 @@
#define QLA_VERSION_MAJOR 3
#define QLA_VERSION_MINOR 10
#define QLA_VERSION_BUILD 34
#define QLA_VERSION_BUILD 35
#endif /* #ifndef _QL_VER_H_ */