diff options
author | np <np@FreeBSD.org> | 2015-04-07 15:32:43 +0000 |
---|---|---|
committer | np <np@FreeBSD.org> | 2015-04-07 15:32:43 +0000 |
commit | 4ecf57ea74e2cc638f27daaea33bc9b2ab4c5836 (patch) | |
tree | 2e6b35a34256d22490c9a7b6ae8125a915fc2e38 /sys/dev | |
parent | 74410b7b36dc098c46c4523ad01075b57581211c (diff) | |
download | FreeBSD-src-4ecf57ea74e2cc638f27daaea33bc9b2ab4c5836.zip FreeBSD-src-4ecf57ea74e2cc638f27daaea33bc9b2ab4c5836.tar.gz |
MFC r274456:
Fix some bad interaction between cxgbe(4) and lacp lagg(4) that could
leave a port permanently disabled when a copper cable is unplugged and
then plugged right back in.
lacp_linkstate goes looking for the current ifmedia on a link state
change and it could get stale information from cxgbe(4) on a module
unplug followed by replug. The fix is to process module events before
link-state events within the driver, and to always rebuild the ifmedia
list on a module change event (instead of rebuilding it lazily).
Thanks to asomers@ for the problem report and detailed analysis to go
with it.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/cxgbe/common/t4_hw.c | 8 | ||||
-rw-r--r-- | sys/dev/cxgbe/t4_main.c | 12 |
2 files changed, 12 insertions, 8 deletions
diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c index 4287a81..a0f7ab2 100644 --- a/sys/dev/cxgbe/common/t4_hw.c +++ b/sys/dev/cxgbe/common/t4_hw.c @@ -5417,6 +5417,10 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) } lc = &pi->link_cfg; + if (mod != pi->mod_type) { + pi->mod_type = mod; + t4_os_portmod_changed(adap, i); + } if (link_ok != lc->link_ok || speed != lc->speed || fc != lc->fc) { /* something changed */ int reason; @@ -5432,10 +5436,6 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) lc->supported = ntohs(p->u.info.pcap); t4_os_link_changed(adap, i, link_ok, reason); } - if (mod != pi->mod_type) { - pi->mod_type = mod; - t4_os_portmod_changed(adap, i); - } } else { CH_WARN_RATELIMIT(adap, "Unknown firmware reply 0x%x (0x%x)\n", opcode, action); diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index 6954b71..3361871 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -1483,7 +1483,9 @@ cxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) struct ifmedia *media = NULL; struct ifmedia_entry *cur; int speed = pi->link_cfg.speed; +#ifdef INVARIANTS int data = (pi->port_type << 8) | pi->mod_type; +#endif if (ifp == pi->ifp) media = &pi->media; @@ -1494,10 +1496,7 @@ cxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) MPASS(media != NULL); cur = media->ifm_cur; - if (cur->ifm_data != data) { - build_medialist(pi, media); - cur = media->ifm_cur; - } + MPASS(cur->ifm_data == data); ifmr->ifm_status = IFM_AVALID; if (!pi->link_cfg.link_ok) @@ -7903,6 +7902,11 @@ t4_os_portmod_changed(const struct adapter *sc, int idx) NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" }; + build_medialist(pi, &pi->media); +#ifdef DEV_NETMAP + build_medialist(pi, &pi->nm_media); +#endif + if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) if_printf(pi->ifp, "transceiver unplugged.\n"); else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) |