Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

qeth: Support VEPA mode

The existing port isolation mode 'forward' will now verify that the adjacent
switch port supports the required reflective relay (RR) mode. This patch adds
the required error handling for the cases where enabling port isolation mode
'forward' can now fail.
Furthermore, once established, we never fall back from one of the port
isolation modes to a non-isolated mode without further user-interaction.
This includes cases where the isolation mode was enabled successfully, but
ceases to work e.g. due to configuration changes at the switch port.
Finally, configuring an isolation mode with the device being offline
will make onlining the device fail permanently upon errors encountered until
either errors are resolved or the isolation mode is changed by the user to a
different mode.

Signed-off-by: Stefan Raspl <raspl@linux.vnet.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Reviewed-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Stefan Raspl and committed by
David S. Miller
0f54761d eb3fb0ba

+112 -67
+4 -1
drivers/s390/net/qeth_core.h
··· 678 678 int performance_stats; 679 679 int rx_sg_cb; 680 680 enum qeth_ipa_isolation_modes isolation; 681 + enum qeth_ipa_isolation_modes prev_isolation; 681 682 int sniffer; 682 683 enum qeth_cq cq; 683 684 char hsuid[9]; ··· 790 789 struct qeth_rx rx; 791 790 struct delayed_work buffer_reclaim_work; 792 791 int reclaim_index; 792 + struct work_struct close_dev_work; 793 793 }; 794 794 795 795 struct qeth_card_list_struct { ··· 927 925 void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *); 928 926 void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...); 929 927 int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *); 930 - int qeth_set_access_ctrl_online(struct qeth_card *card); 928 + int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback); 931 929 int qeth_hdr_chk_and_bounce(struct sk_buff *, int); 932 930 int qeth_configure_cq(struct qeth_card *, enum qeth_cq); 933 931 int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action); 934 932 int qeth_query_ipassists(struct qeth_card *, enum qeth_prot_versions prot); 935 933 void qeth_trace_features(struct qeth_card *); 934 + void qeth_close_dev(struct qeth_card *); 936 935 937 936 /* exports for OSN */ 938 937 int qeth_osn_assist(struct net_device *, void *, int);
+84 -51
drivers/s390/net/qeth_core_main.c
··· 68 68 enum qeth_qdio_buffer_states newbufstate); 69 69 static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int); 70 70 71 + static struct workqueue_struct *qeth_wq; 72 + 73 + static void qeth_close_dev_handler(struct work_struct *work) 74 + { 75 + struct qeth_card *card; 76 + 77 + card = container_of(work, struct qeth_card, close_dev_work); 78 + QETH_CARD_TEXT(card, 2, "cldevhdl"); 79 + rtnl_lock(); 80 + dev_close(card->dev); 81 + rtnl_unlock(); 82 + ccwgroup_set_offline(card->gdev); 83 + } 84 + 85 + void qeth_close_dev(struct qeth_card *card) 86 + { 87 + QETH_CARD_TEXT(card, 2, "cldevsubm"); 88 + queue_work(qeth_wq, &card->close_dev_work); 89 + } 90 + EXPORT_SYMBOL_GPL(qeth_close_dev); 91 + 71 92 static inline const char *qeth_get_cardname(struct qeth_card *card) 72 93 { 73 94 if (card->info.guestlan) { ··· 563 542 } else { 564 543 switch (cmd->hdr.command) { 565 544 case IPA_CMD_STOPLAN: 566 - dev_warn(&card->gdev->dev, 545 + if (cmd->hdr.return_code == 546 + IPA_RC_VEPA_TO_VEB_TRANSITION) { 547 + dev_err(&card->gdev->dev, 548 + "Interface %s is down because the " 549 + "adjacent port is no longer in " 550 + "reflective relay mode\n", 551 + QETH_CARD_IFNAME(card)); 552 + qeth_close_dev(card); 553 + } else { 554 + dev_warn(&card->gdev->dev, 567 555 "The link for interface %s on CHPID" 568 556 " 0x%X failed\n", 569 557 QETH_CARD_IFNAME(card), 570 558 card->info.chpid); 559 + qeth_issue_ipa_msg(cmd, 560 + cmd->hdr.return_code, card); 561 + } 571 562 card->lan_online = 0; 572 563 if (card->dev && netif_carrier_ok(card->dev)) 573 564 netif_carrier_off(card->dev); ··· 1449 1416 /* init QDIO stuff */ 1450 1417 qeth_init_qdio_info(card); 1451 1418 INIT_DELAYED_WORK(&card->buffer_reclaim_work, qeth_buffer_reclaim_work); 1419 + INIT_WORK(&card->close_dev_work, qeth_close_dev_handler); 1452 1420 return 0; 1453 1421 } 1454 1422 ··· 4091 4057 { 4092 4058 struct qeth_ipa_cmd *cmd; 4093 4059 struct qeth_set_access_ctrl *access_ctrl_req; 4060 + int fallback = *(int *)reply->param; 4094 4061 4095 4062 QETH_CARD_TEXT(card, 4, "setaccb"); 4096 4063 ··· 4101 4066 QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name); 4102 4067 QETH_DBF_TEXT_(SETUP, 2, "rc=%d", 4103 4068 cmd->data.setadapterparms.hdr.return_code); 4069 + if (cmd->data.setadapterparms.hdr.return_code != 4070 + SET_ACCESS_CTRL_RC_SUCCESS) 4071 + QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n", 4072 + card->gdev->dev.kobj.name, 4073 + access_ctrl_req->subcmd_code, 4074 + cmd->data.setadapterparms.hdr.return_code); 4104 4075 switch (cmd->data.setadapterparms.hdr.return_code) { 4105 4076 case SET_ACCESS_CTRL_RC_SUCCESS: 4106 - case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED: 4107 - case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED: 4108 - { 4109 - card->options.isolation = access_ctrl_req->subcmd_code; 4110 4077 if (card->options.isolation == ISOLATION_MODE_NONE) { 4111 4078 dev_info(&card->gdev->dev, 4112 4079 "QDIO data connection isolation is deactivated\n"); ··· 4116 4079 dev_info(&card->gdev->dev, 4117 4080 "QDIO data connection isolation is activated\n"); 4118 4081 } 4119 - QETH_DBF_MESSAGE(3, "OK:SET_ACCESS_CTRL(%s, %d)==%d\n", 4120 - card->gdev->dev.kobj.name, 4121 - access_ctrl_req->subcmd_code, 4122 - cmd->data.setadapterparms.hdr.return_code); 4123 4082 break; 4124 - } 4083 + case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED: 4084 + QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already " 4085 + "deactivated\n", dev_name(&card->gdev->dev)); 4086 + if (fallback) 4087 + card->options.isolation = card->options.prev_isolation; 4088 + break; 4089 + case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED: 4090 + QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already" 4091 + " activated\n", dev_name(&card->gdev->dev)); 4092 + if (fallback) 4093 + card->options.isolation = card->options.prev_isolation; 4094 + break; 4125 4095 case SET_ACCESS_CTRL_RC_NOT_SUPPORTED: 4126 - { 4127 - QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n", 4128 - card->gdev->dev.kobj.name, 4129 - access_ctrl_req->subcmd_code, 4130 - cmd->data.setadapterparms.hdr.return_code); 4131 4096 dev_err(&card->gdev->dev, "Adapter does not " 4132 4097 "support QDIO data connection isolation\n"); 4133 - 4134 - /* ensure isolation mode is "none" */ 4135 - card->options.isolation = ISOLATION_MODE_NONE; 4136 4098 break; 4137 - } 4138 4099 case SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER: 4139 - { 4140 - QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n", 4141 - card->gdev->dev.kobj.name, 4142 - access_ctrl_req->subcmd_code, 4143 - cmd->data.setadapterparms.hdr.return_code); 4144 4100 dev_err(&card->gdev->dev, 4145 4101 "Adapter is dedicated. " 4146 4102 "QDIO data connection isolation not supported\n"); 4147 - 4148 - /* ensure isolation mode is "none" */ 4149 - card->options.isolation = ISOLATION_MODE_NONE; 4103 + if (fallback) 4104 + card->options.isolation = card->options.prev_isolation; 4150 4105 break; 4151 - } 4152 4106 case SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF: 4153 - { 4154 - QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n", 4155 - card->gdev->dev.kobj.name, 4156 - access_ctrl_req->subcmd_code, 4157 - cmd->data.setadapterparms.hdr.return_code); 4158 4107 dev_err(&card->gdev->dev, 4159 4108 "TSO does not permit QDIO data connection isolation\n"); 4160 - 4161 - /* ensure isolation mode is "none" */ 4162 - card->options.isolation = ISOLATION_MODE_NONE; 4109 + if (fallback) 4110 + card->options.isolation = card->options.prev_isolation; 4163 4111 break; 4164 - } 4112 + case SET_ACCESS_CTRL_RC_REFLREL_UNSUPPORTED: 4113 + dev_err(&card->gdev->dev, "The adjacent switch port does not " 4114 + "support reflective relay mode\n"); 4115 + if (fallback) 4116 + card->options.isolation = card->options.prev_isolation; 4117 + break; 4118 + case SET_ACCESS_CTRL_RC_REFLREL_FAILED: 4119 + dev_err(&card->gdev->dev, "The reflective relay mode cannot be " 4120 + "enabled at the adjacent switch port"); 4121 + if (fallback) 4122 + card->options.isolation = card->options.prev_isolation; 4123 + break; 4124 + case SET_ACCESS_CTRL_RC_REFLREL_DEACT_FAILED: 4125 + dev_warn(&card->gdev->dev, "Turning off reflective relay mode " 4126 + "at the adjacent switch failed\n"); 4127 + break; 4165 4128 default: 4166 - { 4167 4129 /* this should never happen */ 4168 - QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d" 4169 - "==UNKNOWN\n", 4170 - card->gdev->dev.kobj.name, 4171 - access_ctrl_req->subcmd_code, 4172 - cmd->data.setadapterparms.hdr.return_code); 4173 - 4174 - /* ensure isolation mode is "none" */ 4175 - card->options.isolation = ISOLATION_MODE_NONE; 4130 + if (fallback) 4131 + card->options.isolation = card->options.prev_isolation; 4176 4132 break; 4177 - } 4178 4133 } 4179 4134 qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd); 4180 4135 return 0; 4181 4136 } 4182 4137 4183 4138 static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card, 4184 - enum qeth_ipa_isolation_modes isolation) 4139 + enum qeth_ipa_isolation_modes isolation, int fallback) 4185 4140 { 4186 4141 int rc; 4187 4142 struct qeth_cmd_buffer *iob; ··· 4193 4164 access_ctrl_req->subcmd_code = isolation; 4194 4165 4195 4166 rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_set_access_ctrl_cb, 4196 - NULL); 4167 + &fallback); 4197 4168 QETH_DBF_TEXT_(SETUP, 2, "rc=%d", rc); 4198 4169 return rc; 4199 4170 } 4200 4171 4201 - int qeth_set_access_ctrl_online(struct qeth_card *card) 4172 + int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback) 4202 4173 { 4203 4174 int rc = 0; 4204 4175 ··· 4208 4179 card->info.type == QETH_CARD_TYPE_OSX) && 4209 4180 qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) { 4210 4181 rc = qeth_setadpparms_set_access_ctrl(card, 4211 - card->options.isolation); 4182 + card->options.isolation, fallback); 4212 4183 if (rc) { 4213 4184 QETH_DBF_MESSAGE(3, 4214 4185 "IPA(SET_ACCESS_CTRL,%s,%d) sent failed\n", 4215 4186 card->gdev->dev.kobj.name, 4216 4187 rc); 4188 + rc = -EOPNOTSUPP; 4217 4189 } 4218 4190 } else if (card->options.isolation != ISOLATION_MODE_NONE) { 4219 4191 card->options.isolation = ISOLATION_MODE_NONE; ··· 5582 5552 rwlock_init(&qeth_core_card_list.rwlock); 5583 5553 mutex_init(&qeth_mod_mutex); 5584 5554 5555 + qeth_wq = create_singlethread_workqueue("qeth_wq"); 5556 + 5585 5557 rc = qeth_register_dbf_views(); 5586 5558 if (rc) 5587 5559 goto out_err; ··· 5630 5598 5631 5599 static void __exit qeth_core_exit(void) 5632 5600 { 5601 + destroy_workqueue(qeth_wq); 5633 5602 ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); 5634 5603 ccw_driver_unregister(&qeth_ccw_driver); 5635 5604 kmem_cache_destroy(qeth_qdio_outbuf_cache);
+1
drivers/s390/net/qeth_core_mpc.c
··· 204 204 {IPA_RC_INVALID_SETRTG_INDICATOR, "Invalid SETRTG indicator"}, 205 205 {IPA_RC_MC_ADDR_ALREADY_DEFINED, "Multicast address already defined"}, 206 206 {IPA_RC_LAN_OFFLINE, "STRTLAN_LAN_DISABLED - LAN offline"}, 207 + {IPA_RC_VEPA_TO_VEB_TRANSITION, "Adj. switch disabled port mode RR"}, 207 208 {IPA_RC_INVALID_IP_VERSION2, "Invalid IP version"}, 208 209 {IPA_RC_ENOMEM, "Memory problem"}, 209 210 {IPA_RC_FFFF, "Unknown Error"}
+5
drivers/s390/net/qeth_core_mpc.h
··· 177 177 IPA_RC_INVALID_SETRTG_INDICATOR = 0xe012, 178 178 IPA_RC_MC_ADDR_ALREADY_DEFINED = 0xe013, 179 179 IPA_RC_LAN_OFFLINE = 0xe080, 180 + IPA_RC_VEPA_TO_VEB_TRANSITION = 0xe090, 180 181 IPA_RC_INVALID_IP_VERSION2 = 0xf001, 181 182 IPA_RC_ENOMEM = 0xfffe, 182 183 IPA_RC_FFFF = 0xffff ··· 270 269 SET_ACCESS_CTRL_RC_ALREADY_ISOLATED = 0x0010, 271 270 SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER = 0x0014, 272 271 SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF = 0x0018, 272 + SET_ACCESS_CTRL_RC_REFLREL_UNSUPPORTED = 0x0022, 273 + SET_ACCESS_CTRL_RC_REFLREL_FAILED = 0x0024, 274 + SET_ACCESS_CTRL_RC_REFLREL_DEACT_FAILED = 0x0028, 273 275 }; 274 276 275 277 ··· 390 386 /* SET_ACCESS_CONTROL: same format for request and reply */ 391 387 struct qeth_set_access_ctrl { 392 388 __u32 subcmd_code; 389 + __u8 reserved[8]; 393 390 } __attribute__((packed)); 394 391 395 392 struct qeth_query_oat {
+2 -1
drivers/s390/net/qeth_core_sys.c
··· 513 513 rc = count; 514 514 515 515 /* defer IP assist if device is offline (until discipline->set_online)*/ 516 + card->options.prev_isolation = card->options.isolation; 516 517 card->options.isolation = isolation; 517 518 if (card->state == CARD_STATE_SOFTSETUP || 518 519 card->state == CARD_STATE_UP) { 519 - int ipa_rc = qeth_set_access_ctrl_online(card); 520 + int ipa_rc = qeth_set_access_ctrl_online(card, 1); 520 521 if (ipa_rc != 0) 521 522 rc = ipa_rc; 522 523 }
+9 -7
drivers/s390/net/qeth_l2_main.c
··· 1025 1025 1026 1026 contin: 1027 1027 if ((card->info.type == QETH_CARD_TYPE_OSD) || 1028 - (card->info.type == QETH_CARD_TYPE_OSX)) 1028 + (card->info.type == QETH_CARD_TYPE_OSX)) { 1029 1029 /* configure isolation level */ 1030 - qeth_set_access_ctrl_online(card); 1030 + rc = qeth_set_access_ctrl_online(card, 0); 1031 + if (rc) { 1032 + rc = -ENODEV; 1033 + goto out_remove; 1034 + } 1035 + } 1031 1036 1032 1037 if (card->info.type != QETH_CARD_TYPE_OSN && 1033 1038 card->info.type != QETH_CARD_TYPE_OSM) ··· 1149 1144 dev_info(&card->gdev->dev, 1150 1145 "Device successfully recovered!\n"); 1151 1146 else { 1152 - if (rtnl_trylock()) { 1153 - dev_close(card->dev); 1154 - rtnl_unlock(); 1155 - dev_warn(&card->gdev->dev, "The qeth device driver " 1147 + qeth_close_dev(card); 1148 + dev_warn(&card->gdev->dev, "The qeth device driver " 1156 1149 "failed to recover an error on the device\n"); 1157 - } 1158 1150 } 1159 1151 qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); 1160 1152 qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
+7 -7
drivers/s390/net/qeth_l3_main.c
··· 1449 1449 { 1450 1450 QETH_CARD_TEXT(card, 3, "strtipas"); 1451 1451 1452 - qeth_set_access_ctrl_online(card); /* go on*/ 1452 + if (qeth_set_access_ctrl_online(card, 0)) 1453 + return -EIO; 1453 1454 qeth_l3_start_ipa_arp_processing(card); /* go on*/ 1454 1455 qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/ 1455 1456 qeth_l3_start_ipa_source_mac(card); /* go on*/ ··· 3389 3388 QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); 3390 3389 if (!card->options.sniffer) { 3391 3390 rc = qeth_l3_start_ipassists(card); 3392 - if (rc) 3391 + if (rc) { 3393 3392 QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); 3393 + goto out_remove; 3394 + } 3394 3395 rc = qeth_l3_setrouting_v4(card); 3395 3396 if (rc) 3396 3397 QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); ··· 3514 3511 dev_info(&card->gdev->dev, 3515 3512 "Device successfully recovered!\n"); 3516 3513 else { 3517 - if (rtnl_trylock()) { 3518 - dev_close(card->dev); 3519 - rtnl_unlock(); 3520 - dev_warn(&card->gdev->dev, "The qeth device driver " 3514 + qeth_close_dev(card); 3515 + dev_warn(&card->gdev->dev, "The qeth device driver " 3521 3516 "failed to recover an error on the device\n"); 3522 - } 3523 3517 } 3524 3518 qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); 3525 3519 qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);