Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/cxgbe/cxgbei/cxgbei.c
Show First 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
#include "tom/t4_tom.h" | #include "tom/t4_tom.h" | ||||
#include "cxgbei.h" | #include "cxgbei.h" | ||||
static int worker_thread_count; | static int worker_thread_count; | ||||
static struct cxgbei_worker_thread_softc *cwt_softc; | static struct cxgbei_worker_thread_softc *cwt_softc; | ||||
static struct proc *cxgbei_proc; | static struct proc *cxgbei_proc; | ||||
static void | static void | ||||
free_ci_counters(struct cxgbei_data *ci) | |||||
{ | |||||
#define FREE_CI_COUNTER(x) do { \ | |||||
if (ci->x != NULL) { \ | |||||
counter_u64_free(ci->x); \ | |||||
ci->x = NULL; \ | |||||
} \ | |||||
} while (0) | |||||
FREE_CI_COUNTER(ddp_setup_ok); | |||||
FREE_CI_COUNTER(ddp_setup_error); | |||||
FREE_CI_COUNTER(ddp_bytes); | |||||
FREE_CI_COUNTER(ddp_pdus); | |||||
FREE_CI_COUNTER(fl_bytes); | |||||
FREE_CI_COUNTER(fl_pdus); | |||||
#undef FREE_CI_COUNTER | |||||
} | |||||
static int | |||||
alloc_ci_counters(struct cxgbei_data *ci) | |||||
{ | |||||
#define ALLOC_CI_COUNTER(x) do { \ | |||||
ci->x = counter_u64_alloc(M_WAITOK); \ | |||||
if (ci->x == NULL) \ | |||||
goto fail; \ | |||||
} while (0) | |||||
ALLOC_CI_COUNTER(ddp_setup_ok); | |||||
ALLOC_CI_COUNTER(ddp_setup_error); | |||||
ALLOC_CI_COUNTER(ddp_bytes); | |||||
ALLOC_CI_COUNTER(ddp_pdus); | |||||
ALLOC_CI_COUNTER(fl_bytes); | |||||
ALLOC_CI_COUNTER(fl_pdus); | |||||
#undef ALLOC_CI_COUNTER | |||||
return (0); | |||||
fail: | |||||
free_ci_counters(ci); | |||||
return (ENOMEM); | |||||
} | |||||
static void | |||||
read_pdu_limits(struct adapter *sc, uint32_t *max_tx_pdu_len, | read_pdu_limits(struct adapter *sc, uint32_t *max_tx_pdu_len, | ||||
uint32_t *max_rx_pdu_len) | uint32_t *max_rx_pdu_len) | ||||
{ | { | ||||
uint32_t tx_len, rx_len, r, v; | uint32_t tx_len, rx_len, r, v; | ||||
rx_len = t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE); | rx_len = t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE); | ||||
tx_len = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); | tx_len = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); | ||||
Show All 25 Lines | cxgbei_init(struct adapter *sc, struct cxgbei_data *ci) | ||||
struct sysctl_oid_list *children; | struct sysctl_oid_list *children; | ||||
struct ppod_region *pr; | struct ppod_region *pr; | ||||
uint32_t r; | uint32_t r; | ||||
int rc; | int rc; | ||||
MPASS(sc->vres.iscsi.size > 0); | MPASS(sc->vres.iscsi.size > 0); | ||||
MPASS(ci != NULL); | MPASS(ci != NULL); | ||||
rc = alloc_ci_counters(ci); | |||||
if (rc != 0) | |||||
return (rc); | |||||
read_pdu_limits(sc, &ci->max_tx_pdu_len, &ci->max_rx_pdu_len); | read_pdu_limits(sc, &ci->max_tx_pdu_len, &ci->max_rx_pdu_len); | ||||
pr = &ci->pr; | pr = &ci->pr; | ||||
r = t4_read_reg(sc, A_ULP_RX_ISCSI_PSZ); | r = t4_read_reg(sc, A_ULP_RX_ISCSI_PSZ); | ||||
rc = t4_init_ppod_region(pr, &sc->vres.iscsi, r, "iSCSI page pods"); | rc = t4_init_ppod_region(pr, &sc->vres.iscsi, r, "iSCSI page pods"); | ||||
if (rc != 0) { | if (rc != 0) { | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"%s: failed to initialize the iSCSI page pod region: %u.\n", | "%s: failed to initialize the iSCSI page pod region: %u.\n", | ||||
__func__, rc); | __func__, rc); | ||||
free_ci_counters(ci); | |||||
return (rc); | return (rc); | ||||
} | } | ||||
r = t4_read_reg(sc, A_ULP_RX_ISCSI_TAGMASK); | r = t4_read_reg(sc, A_ULP_RX_ISCSI_TAGMASK); | ||||
r &= V_ISCSITAGMASK(M_ISCSITAGMASK); | r &= V_ISCSITAGMASK(M_ISCSITAGMASK); | ||||
if (r != pr->pr_tag_mask) { | if (r != pr->pr_tag_mask) { | ||||
/* | /* | ||||
* Recent firmwares are supposed to set up the iSCSI tagmask | * Recent firmwares are supposed to set up the iSCSI tagmask | ||||
* but we'll do it ourselves it the computed value doesn't match | * but we'll do it ourselves it the computed value doesn't match | ||||
* what's in the register. | * what's in the register. | ||||
*/ | */ | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"tagmask 0x%08x does not match computed mask 0x%08x.\n", r, | "tagmask 0x%08x does not match computed mask 0x%08x.\n", r, | ||||
pr->pr_tag_mask); | pr->pr_tag_mask); | ||||
t4_set_reg_field(sc, A_ULP_RX_ISCSI_TAGMASK, | t4_set_reg_field(sc, A_ULP_RX_ISCSI_TAGMASK, | ||||
V_ISCSITAGMASK(M_ISCSITAGMASK), pr->pr_tag_mask); | V_ISCSITAGMASK(M_ISCSITAGMASK), pr->pr_tag_mask); | ||||
} | } | ||||
sysctl_ctx_init(&ci->ctx); | sysctl_ctx_init(&ci->ctx); | ||||
oid = device_get_sysctl_tree(sc->dev); /* dev.t5nex.X */ | oid = device_get_sysctl_tree(sc->dev); /* dev.t5nex.X */ | ||||
children = SYSCTL_CHILDREN(oid); | children = SYSCTL_CHILDREN(oid); | ||||
oid = SYSCTL_ADD_NODE(&ci->ctx, children, OID_AUTO, "iscsi", | oid = SYSCTL_ADD_NODE(&ci->ctx, children, OID_AUTO, "iscsi", | ||||
CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "iSCSI ULP statistics"); | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "iSCSI ULP settings"); | ||||
children = SYSCTL_CHILDREN(oid); | children = SYSCTL_CHILDREN(oid); | ||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "ddp_setup_ok", | |||||
CTLFLAG_RD, &ci->ddp_setup_ok, | |||||
"# of times DDP buffer was setup successfully."); | |||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "ddp_setup_error", | |||||
CTLFLAG_RD, &ci->ddp_setup_error, | |||||
"# of times DDP buffer setup failed."); | |||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "ddp_bytes", | |||||
CTLFLAG_RD, &ci->ddp_bytes, "# of bytes placed directly"); | |||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "ddp_pdus", | |||||
CTLFLAG_RD, &ci->ddp_pdus, "# of PDUs with data placed directly."); | |||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "fl_bytes", | |||||
CTLFLAG_RD, &ci->fl_bytes, "# of data bytes delivered in freelist"); | |||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "fl_pdus", | |||||
CTLFLAG_RD, &ci->fl_pdus, | |||||
"# of PDUs with data delivered in freelist"); | |||||
ci->ddp_threshold = 2048; | ci->ddp_threshold = 2048; | ||||
SYSCTL_ADD_UINT(&ci->ctx, children, OID_AUTO, "ddp_threshold", | SYSCTL_ADD_UINT(&ci->ctx, children, OID_AUTO, "ddp_threshold", | ||||
CTLFLAG_RW, &ci->ddp_threshold, 0, "Rx zero copy threshold"); | CTLFLAG_RW, &ci->ddp_threshold, 0, "Rx zero copy threshold"); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
Show All 32 Lines | #endif | ||||
m_freem(m); | m_freem(m); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
do_rx_iscsi_data(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) | do_rx_iscsi_data(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) | ||||
{ | { | ||||
struct adapter *sc = iq->adapter; | struct adapter *sc = iq->adapter; | ||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc; | |||||
struct cpl_iscsi_data *cpl = mtod(m, struct cpl_iscsi_data *); | struct cpl_iscsi_data *cpl = mtod(m, struct cpl_iscsi_data *); | ||||
u_int tid = GET_TID(cpl); | u_int tid = GET_TID(cpl); | ||||
struct toepcb *toep = lookup_tid(sc, tid); | struct toepcb *toep = lookup_tid(sc, tid); | ||||
struct icl_cxgbei_pdu *icp = toep->ulpcb2; | struct icl_cxgbei_pdu *icp = toep->ulpcb2; | ||||
M_ASSERTPKTHDR(m); | M_ASSERTPKTHDR(m); | ||||
MPASS(m->m_pkthdr.len == be16toh(cpl->len) + sizeof(*cpl)); | MPASS(m->m_pkthdr.len == be16toh(cpl->len) + sizeof(*cpl)); | ||||
/* Must already have received the header (but not the data). */ | /* Must already have received the header (but not the data). */ | ||||
MPASS(icp != NULL); | MPASS(icp != NULL); | ||||
MPASS(icp->icp_flags == ICPF_RX_HDR); | MPASS(icp->icp_flags == ICPF_RX_HDR); | ||||
MPASS(icp->ip.ip_data_mbuf == NULL); | MPASS(icp->ip.ip_data_mbuf == NULL); | ||||
m_adj(m, sizeof(*cpl)); | m_adj(m, sizeof(*cpl)); | ||||
MPASS(icp->ip.ip_data_len == m->m_pkthdr.len); | MPASS(icp->ip.ip_data_len == m->m_pkthdr.len); | ||||
icp->icp_flags |= ICPF_RX_FLBUF; | icp->icp_flags |= ICPF_RX_FLBUF; | ||||
icp->ip.ip_data_mbuf = m; | icp->ip.ip_data_mbuf = m; | ||||
counter_u64_add(ci->fl_pdus, 1); | toep->ofld_rxq->rx_iscsi_fl_pdus++; | ||||
counter_u64_add(ci->fl_bytes, m->m_pkthdr.len); | toep->ofld_rxq->rx_iscsi_fl_octets += m->m_pkthdr.len; | ||||
#if 0 | #if 0 | ||||
CTR3(KTR_CXGBE, "%s: tid %u, cpl->len %u", __func__, tid, | CTR3(KTR_CXGBE, "%s: tid %u, cpl->len %u", __func__, tid, | ||||
be16toh(cpl->len)); | be16toh(cpl->len)); | ||||
#endif | #endif | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
do_rx_iscsi_ddp(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) | do_rx_iscsi_ddp(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) | ||||
{ | { | ||||
struct adapter *sc = iq->adapter; | struct adapter *sc = iq->adapter; | ||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc; | |||||
const struct cpl_rx_data_ddp *cpl = (const void *)(rss + 1); | const struct cpl_rx_data_ddp *cpl = (const void *)(rss + 1); | ||||
u_int tid = GET_TID(cpl); | u_int tid = GET_TID(cpl); | ||||
struct toepcb *toep = lookup_tid(sc, tid); | struct toepcb *toep = lookup_tid(sc, tid); | ||||
struct inpcb *inp = toep->inp; | struct inpcb *inp = toep->inp; | ||||
struct socket *so; | struct socket *so; | ||||
struct sockbuf *sb; | struct sockbuf *sb; | ||||
struct tcpcb *tp; | struct tcpcb *tp; | ||||
struct icl_cxgbei_conn *icc; | struct icl_cxgbei_conn *icc; | ||||
Show All 26 Lines | #endif | ||||
if (val & F_DDP_HDRCRC_ERR) | if (val & F_DDP_HDRCRC_ERR) | ||||
icp->icp_flags |= ICPF_HCRC_ERR; | icp->icp_flags |= ICPF_HCRC_ERR; | ||||
if (val & F_DDP_DATACRC_ERR) | if (val & F_DDP_DATACRC_ERR) | ||||
icp->icp_flags |= ICPF_DCRC_ERR; | icp->icp_flags |= ICPF_DCRC_ERR; | ||||
if (val & F_DDP_PDU && ip->ip_data_mbuf == NULL) { | if (val & F_DDP_PDU && ip->ip_data_mbuf == NULL) { | ||||
MPASS((icp->icp_flags & ICPF_RX_FLBUF) == 0); | MPASS((icp->icp_flags & ICPF_RX_FLBUF) == 0); | ||||
MPASS(ip->ip_data_len > 0); | MPASS(ip->ip_data_len > 0); | ||||
icp->icp_flags |= ICPF_RX_DDP; | icp->icp_flags |= ICPF_RX_DDP; | ||||
counter_u64_add(ci->ddp_pdus, 1); | toep->ofld_rxq->rx_iscsi_ddp_pdus++; | ||||
counter_u64_add(ci->ddp_bytes, ip->ip_data_len); | toep->ofld_rxq->rx_iscsi_ddp_octets += ip->ip_data_len; | ||||
} | } | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
if (__predict_false(inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT))) { | if (__predict_false(inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT))) { | ||||
CTR4(KTR_CXGBE, "%s: tid %u, rx (%d bytes), inp_flags 0x%x", | CTR4(KTR_CXGBE, "%s: tid %u, rx (%d bytes), inp_flags 0x%x", | ||||
__func__, tid, pdu_len, inp->inp_flags); | __func__, tid, pdu_len, inp->inp_flags); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
icl_cxgbei_conn_pdu_free(NULL, ip); | icl_cxgbei_conn_pdu_free(NULL, ip); | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc; | struct cxgbei_data *ci = sc->iscsi_ulp_softc; | ||||
ASSERT_SYNCHRONIZED_OP(sc); | ASSERT_SYNCHRONIZED_OP(sc); | ||||
if (ci != NULL) { | if (ci != NULL) { | ||||
sysctl_ctx_free(&ci->ctx); | sysctl_ctx_free(&ci->ctx); | ||||
t4_free_ppod_region(&ci->pr); | t4_free_ppod_region(&ci->pr); | ||||
free_ci_counters(ci); | |||||
free(ci, M_CXGBE); | free(ci, M_CXGBE); | ||||
sc->iscsi_ulp_softc = NULL; | sc->iscsi_ulp_softc = NULL; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 285 Lines • Show Last 20 Lines |