summaryrefslogtreecommitdiffstats
path: root/drivers/s390/net/qeth_l2_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/net/qeth_l2_main.c')
-rw-r--r--drivers/s390/net/qeth_l2_main.c87
1 files changed, 60 insertions, 27 deletions
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 1b07f382d74c..ad110abfdd47 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -21,6 +21,7 @@
#include <linux/hash.h>
#include <linux/hashtable.h>
#include <linux/string.h>
+#include <asm/setup.h>
#include "qeth_core.h"
#include "qeth_l2.h"
@@ -505,9 +506,19 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
int rc = 0;
char vendor_pre[] = {0x02, 0x00, 0x00};
- QETH_DBF_TEXT(SETUP, 2, "doL2init");
+ QETH_DBF_TEXT(SETUP, 2, "l2reqmac");
QETH_DBF_TEXT_(SETUP, 2, "doL2%s", CARD_BUS_ID(card));
+ if (MACHINE_IS_VM) {
+ rc = qeth_vm_request_mac(card);
+ if (!rc)
+ goto out;
+ QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %s: x%x\n",
+ CARD_BUS_ID(card), rc);
+ QETH_DBF_TEXT_(SETUP, 2, "err%04x", rc);
+ /* fall back to alternative mechanism: */
+ }
+
if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) {
rc = qeth_query_setadapterparms(card);
if (rc) {
@@ -528,11 +539,12 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
QETH_DBF_TEXT_(SETUP, 2, "1err%04x", rc);
return rc;
}
- QETH_DBF_HEX(SETUP, 2, card->dev->dev_addr, OSA_ADDR_LEN);
} else {
eth_random_addr(card->dev->dev_addr);
memcpy(card->dev->dev_addr, vendor_pre, 3);
}
+out:
+ QETH_DBF_HEX(SETUP, 2, card->dev->dev_addr, card->dev->addr_len);
return 0;
}
@@ -759,8 +771,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,
sizeof(struct qeth_hdr));
if (!new_skb)
goto tx_drop;
- hdr = (struct qeth_hdr *)skb_push(new_skb,
- sizeof(struct qeth_hdr));
+ hdr = skb_push(new_skb, sizeof(struct qeth_hdr));
skb_set_mac_header(new_skb, sizeof(struct qeth_hdr));
qeth_l2_fill_header(card, hdr, new_skb, cast_type);
if (new_skb->ip_summed == CHECKSUM_PARTIAL)
@@ -880,11 +891,21 @@ static int qeth_l2_stop(struct net_device *dev)
return 0;
}
+static const struct device_type qeth_l2_devtype = {
+ .name = "qeth_layer2",
+ .groups = qeth_l2_attr_groups,
+};
+
static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+ int rc;
- qeth_l2_create_device_attributes(&gdev->dev);
+ if (gdev->dev.type == &qeth_generic_devtype) {
+ rc = qeth_l2_create_device_attributes(&gdev->dev);
+ if (rc)
+ return rc;
+ }
INIT_LIST_HEAD(&card->vid_list);
hash_init(card->mac_htable);
card->options.layer2 = 1;
@@ -896,7 +917,8 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
{
struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
- qeth_l2_remove_device_attributes(&cgdev->dev);
+ if (cgdev->dev.type == &qeth_generic_devtype)
+ qeth_l2_remove_device_attributes(&cgdev->dev);
qeth_set_allowed_threads(card, 0, 1);
wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
@@ -954,7 +976,6 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
case QETH_CARD_TYPE_OSN:
card->dev = alloc_netdev(0, "osn%d", NET_NAME_UNKNOWN,
ether_setup);
- card->dev->flags |= IFF_NOARP;
break;
default:
card->dev = alloc_etherdev(0);
@@ -969,9 +990,12 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
card->dev->min_mtu = 64;
card->dev->max_mtu = ETH_MAX_MTU;
card->dev->netdev_ops = &qeth_l2_netdev_ops;
- card->dev->ethtool_ops =
- (card->info.type != QETH_CARD_TYPE_OSN) ?
- &qeth_l2_ethtool_ops : &qeth_l2_osn_ops;
+ if (card->info.type == QETH_CARD_TYPE_OSN) {
+ card->dev->ethtool_ops = &qeth_l2_osn_ops;
+ card->dev->flags |= IFF_NOARP;
+ } else {
+ card->dev->ethtool_ops = &qeth_l2_ethtool_ops;
+ }
card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) {
card->dev->hw_features = NETIF_F_SG;
@@ -1004,6 +1028,13 @@ static int qeth_l2_start_ipassists(struct qeth_card *card)
return 0;
}
+static void qeth_l2_trace_features(struct qeth_card *card)
+{
+ QETH_CARD_TEXT(card, 2, "l2featur");
+ QETH_CARD_HEX(card, 2, &card->options.sbp.supported_funcs,
+ sizeof(card->options.sbp.supported_funcs));
+}
+
static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
@@ -1027,6 +1058,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
dev_info(&card->gdev->dev,
"The device represents a Bridge Capable Port\n");
qeth_trace_features(card);
+ qeth_l2_trace_features(card);
if (!card->dev && qeth_l2_setup_netdev(card)) {
rc = -ENODEV;
@@ -1269,6 +1301,7 @@ static int qeth_l2_control_event(struct qeth_card *card,
}
struct qeth_discipline qeth_l2_discipline = {
+ .devtype = &qeth_l2_devtype,
.start_poll = qeth_qdio_start_poll,
.input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
.output_handler = (qdio_handler_t *) qeth_qdio_output_handler,
@@ -1629,27 +1662,27 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
if ((is_iqd && (cbctl->ipa_rc == IPA_RC_SUCCESS)) ||
(!is_iqd && (cbctl->ipa_rc == cbctl->cmd_rc)))
switch (cbctl->cmd_rc) {
- case 0x0000:
+ case IPA_RC_SUCCESS:
rc = 0;
break;
- case 0x2B04:
- case 0x0004:
+ case IPA_RC_L2_UNSUPPORTED_CMD:
+ case IPA_RC_UNSUPPORTED_COMMAND:
rc = -EOPNOTSUPP;
break;
- case 0x2B0C:
- case 0x000C: /* Not configured as bridge Port */
+ case IPA_RC_SBP_OSA_NOT_CONFIGURED:
+ case IPA_RC_SBP_IQD_NOT_CONFIGURED:
rc = -ENODEV; /* maybe not the best code here? */
dev_err(&card->gdev->dev,
"The device is not configured as a Bridge Port\n");
break;
- case 0x2B10:
- case 0x0010: /* OS mismatch */
+ case IPA_RC_SBP_OSA_OS_MISMATCH:
+ case IPA_RC_SBP_IQD_OS_MISMATCH:
rc = -EPERM;
dev_err(&card->gdev->dev,
"A Bridge Port is already configured by a different operating system\n");
break;
- case 0x2B14:
- case 0x0014: /* Another device is Primary */
+ case IPA_RC_SBP_OSA_ANO_DEV_PRIMARY:
+ case IPA_RC_SBP_IQD_ANO_DEV_PRIMARY:
switch (setcmd) {
case IPA_SBP_SET_PRIMARY_BRIDGE_PORT:
rc = -EEXIST;
@@ -1665,26 +1698,26 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
rc = -EIO;
}
break;
- case 0x2B18:
- case 0x0018: /* This device is currently Secondary */
+ case IPA_RC_SBP_OSA_CURRENT_SECOND:
+ case IPA_RC_SBP_IQD_CURRENT_SECOND:
rc = -EBUSY;
dev_err(&card->gdev->dev,
"The device is already a secondary Bridge Port\n");
break;
- case 0x2B1C:
- case 0x001C: /* Limit for Secondary devices reached */
+ case IPA_RC_SBP_OSA_LIMIT_SECOND:
+ case IPA_RC_SBP_IQD_LIMIT_SECOND:
rc = -EEXIST;
dev_err(&card->gdev->dev,
"The LAN cannot have more secondary Bridge Ports\n");
break;
- case 0x2B24:
- case 0x0024: /* This device is currently Primary */
+ case IPA_RC_SBP_OSA_CURRENT_PRIMARY:
+ case IPA_RC_SBP_IQD_CURRENT_PRIMARY:
rc = -EBUSY;
dev_err(&card->gdev->dev,
"The device is already a primary Bridge Port\n");
break;
- case 0x2B20:
- case 0x0020: /* Not authorized by zManager */
+ case IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN:
+ case IPA_RC_SBP_IQD_NOT_AUTHD_BY_ZMAN:
rc = -EACCES;
dev_err(&card->gdev->dev,
"The device is not authorized to be a Bridge Port\n");
OpenPOWER on IntegriCloud