aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulian Wiedmann <jwi@linux.vnet.ibm.com>2018-04-19 06:52:09 -0400
committerDavid S. Miller <davem@davemloft.net>2018-04-22 14:42:31 -0400
commitbcacfcbc82b4235d280ed9b067aa4567f4a0c756 (patch)
treed32c15cc4bc8fea3659db08a9d735fb516037591
parenta936b1ef37ce1e996533878f4b23944f9444dcdf (diff)
s390/qeth: fix MAC address update sequence
When changing the MAC address on a L2 qeth device, current code first unregisters the old address, then registers the new one. If HW rejects the new address (or the IO fails), the device ends up with no operable address at all. Re-order the code flow so that the old address only gets dropped if the new address was registered successfully. While at it, add logic to catch some corner-cases. Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/s390/net/qeth_l2_main.c55
1 files changed, 31 insertions, 24 deletions
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 2ad6f12f3d49..36f9b74848fe 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -121,13 +121,10 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
121 QETH_CARD_TEXT(card, 2, "L2Setmac"); 121 QETH_CARD_TEXT(card, 2, "L2Setmac");
122 rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC); 122 rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC);
123 if (rc == 0) { 123 if (rc == 0) {
124 card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
125 ether_addr_copy(card->dev->dev_addr, mac);
126 dev_info(&card->gdev->dev, 124 dev_info(&card->gdev->dev,
127 "MAC address %pM successfully registered on device %s\n", 125 "MAC address %pM successfully registered on device %s\n",
128 card->dev->dev_addr, card->dev->name); 126 mac, card->dev->name);
129 } else { 127 } else {
130 card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
131 switch (rc) { 128 switch (rc) {
132 case -EEXIST: 129 case -EEXIST:
133 dev_warn(&card->gdev->dev, 130 dev_warn(&card->gdev->dev,
@@ -142,19 +139,6 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
142 return rc; 139 return rc;
143} 140}
144 141
145static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac)
146{
147 int rc;
148
149 QETH_CARD_TEXT(card, 2, "L2Delmac");
150 if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
151 return 0;
152 rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELVMAC);
153 if (rc == 0)
154 card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
155 return rc;
156}
157
158static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac) 142static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac)
159{ 143{
160 enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ? 144 enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ?
@@ -519,6 +503,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
519{ 503{
520 struct sockaddr *addr = p; 504 struct sockaddr *addr = p;
521 struct qeth_card *card = dev->ml_priv; 505 struct qeth_card *card = dev->ml_priv;
506 u8 old_addr[ETH_ALEN];
522 int rc = 0; 507 int rc = 0;
523 508
524 QETH_CARD_TEXT(card, 3, "setmac"); 509 QETH_CARD_TEXT(card, 3, "setmac");
@@ -530,14 +515,35 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
530 return -EOPNOTSUPP; 515 return -EOPNOTSUPP;
531 } 516 }
532 QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN); 517 QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN);
518 if (!is_valid_ether_addr(addr->sa_data))
519 return -EADDRNOTAVAIL;
520
533 if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) { 521 if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
534 QETH_CARD_TEXT(card, 3, "setmcREC"); 522 QETH_CARD_TEXT(card, 3, "setmcREC");
535 return -ERESTARTSYS; 523 return -ERESTARTSYS;
536 } 524 }
537 rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]); 525
538 if (!rc || (rc == -ENOENT)) 526 if (!qeth_card_hw_is_reachable(card)) {
539 rc = qeth_l2_send_setmac(card, addr->sa_data); 527 ether_addr_copy(dev->dev_addr, addr->sa_data);
540 return rc ? -EINVAL : 0; 528 return 0;
529 }
530
531 /* don't register the same address twice */
532 if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) &&
533 (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
534 return 0;
535
536 /* add the new address, switch over, drop the old */
537 rc = qeth_l2_send_setmac(card, addr->sa_data);
538 if (rc)
539 return rc;
540 ether_addr_copy(old_addr, dev->dev_addr);
541 ether_addr_copy(dev->dev_addr, addr->sa_data);
542
543 if (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED)
544 qeth_l2_remove_mac(card, old_addr);
545 card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
546 return 0;
541} 547}
542 548
543static void qeth_promisc_to_bridge(struct qeth_card *card) 549static void qeth_promisc_to_bridge(struct qeth_card *card)
@@ -1067,8 +1073,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
1067 goto out_remove; 1073 goto out_remove;
1068 } 1074 }
1069 1075
1070 if (card->info.type != QETH_CARD_TYPE_OSN) 1076 if (card->info.type != QETH_CARD_TYPE_OSN &&
1071 qeth_l2_send_setmac(card, &card->dev->dev_addr[0]); 1077 !qeth_l2_send_setmac(card, card->dev->dev_addr))
1078 card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
1072 1079
1073 if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) { 1080 if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
1074 if (card->info.hwtrap && 1081 if (card->info.hwtrap &&