aboutsummaryrefslogtreecommitdiffstats
path: root/net/ncsi
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2016-10-19 20:45:50 -0400
committerDavid S. Miller <davem@davemloft.net>2016-10-20 11:23:07 -0400
commit008a424a24a904ed12c03b203f6f257bcaf12358 (patch)
tree6529367d9a4a204f17373b606622ae798d0402fc /net/ncsi
parent7ba5c003db59a6f738d87d92b68d4a91cdf22f60 (diff)
net/ncsi: Fix stale link state of inactive channels on failover
The issue was found on BCM5718 which has two NCSI channels in one package: C0 and C1. Both of them are connected to different LANs, means they are in link-up state and C0 is chosen as the active one until resetting BCM5718 happens as below. Resetting BCM5718 results in LSC (Link State Change) AEN packet received on C0, meaning LSC AEN is missed on C1. When LSC AEN packet received on C0 to report link-down, it fails over to C1 because C1 is in link-up state as software can see. However, C1 is in link-down state in hardware. It means the link state is out of synchronization between hardware and software, resulting in inappropriate channel (C1) selected as active one. This resolves the issue by sending separate GLS (Get Link Status) commands to all channels in the package before trying to do failover. The last link states of all channels in the package are retrieved. With it, C0 (not C1) is selected as active one as expected. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ncsi')
-rw-r--r--net/ncsi/internal.h1
-rw-r--r--net/ncsi/ncsi-manage.c28
2 files changed, 28 insertions, 1 deletions
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 13290a70fa71..eac48584cdd1 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -246,6 +246,7 @@ enum {
246 ncsi_dev_state_config_gls, 246 ncsi_dev_state_config_gls,
247 ncsi_dev_state_config_done, 247 ncsi_dev_state_config_done,
248 ncsi_dev_state_suspend_select = 0x0401, 248 ncsi_dev_state_suspend_select = 0x0401,
249 ncsi_dev_state_suspend_gls,
249 ncsi_dev_state_suspend_dcnt, 250 ncsi_dev_state_suspend_dcnt,
250 ncsi_dev_state_suspend_dc, 251 ncsi_dev_state_suspend_dc,
251 ncsi_dev_state_suspend_deselect, 252 ncsi_dev_state_suspend_deselect,
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 655d0d653926..4789f8681695 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -550,12 +550,38 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
550 else 550 else
551 nca.bytes[0] = 1; 551 nca.bytes[0] = 1;
552 552
553 nd->state = ncsi_dev_state_suspend_dcnt; 553 /* To retrieve the last link states of channels in current
554 * package when current active channel needs fail over to
555 * another one. It means we will possibly select another
556 * channel as next active one. The link states of channels
557 * are most important factor of the selection. So we need
558 * accurate link states. Unfortunately, the link states on
559 * inactive channels can't be updated with LSC AEN in time.
560 */
561 if (ndp->flags & NCSI_DEV_RESHUFFLE)
562 nd->state = ncsi_dev_state_suspend_gls;
563 else
564 nd->state = ncsi_dev_state_suspend_dcnt;
554 ret = ncsi_xmit_cmd(&nca); 565 ret = ncsi_xmit_cmd(&nca);
555 if (ret) 566 if (ret)
556 goto error; 567 goto error;
557 568
558 break; 569 break;
570 case ncsi_dev_state_suspend_gls:
571 ndp->pending_req_num = np->channel_num;
572
573 nca.type = NCSI_PKT_CMD_GLS;
574 nca.package = np->id;
575
576 nd->state = ncsi_dev_state_suspend_dcnt;
577 NCSI_FOR_EACH_CHANNEL(np, nc) {
578 nca.channel = nc->id;
579 ret = ncsi_xmit_cmd(&nca);
580 if (ret)
581 goto error;
582 }
583
584 break;
559 case ncsi_dev_state_suspend_dcnt: 585 case ncsi_dev_state_suspend_dcnt:
560 ndp->pending_req_num = 1; 586 ndp->pending_req_num = 1;
561 587