summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authornp <np@FreeBSD.org>2015-04-07 15:32:43 +0000
committernp <np@FreeBSD.org>2015-04-07 15:32:43 +0000
commit4ecf57ea74e2cc638f27daaea33bc9b2ab4c5836 (patch)
tree2e6b35a34256d22490c9a7b6ae8125a915fc2e38 /sys/dev
parent74410b7b36dc098c46c4523ad01075b57581211c (diff)
downloadFreeBSD-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.c8
-rw-r--r--sys/dev/cxgbe/t4_main.c12
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)
OpenPOWER on IntegriCloud