diff options
Diffstat (limited to 'drivers/s390/net/qeth_l3_main.c')
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 343 |
1 files changed, 259 insertions, 84 deletions
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 073b6d354915..fc6ca1da8b98 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/ipv6.h> | 22 | #include <linux/ipv6.h> |
23 | #include <linux/inetdevice.h> | 23 | #include <linux/inetdevice.h> |
24 | #include <linux/igmp.h> | 24 | #include <linux/igmp.h> |
25 | #include <linux/slab.h> | ||
25 | 26 | ||
26 | #include <net/ip.h> | 27 | #include <net/ip.h> |
27 | #include <net/arp.h> | 28 | #include <net/arp.h> |
@@ -41,6 +42,32 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *, | |||
41 | static int __qeth_l3_set_online(struct ccwgroup_device *, int); | 42 | static int __qeth_l3_set_online(struct ccwgroup_device *, int); |
42 | static int __qeth_l3_set_offline(struct ccwgroup_device *, int); | 43 | static int __qeth_l3_set_offline(struct ccwgroup_device *, int); |
43 | 44 | ||
45 | int qeth_l3_set_large_send(struct qeth_card *card, | ||
46 | enum qeth_large_send_types type) | ||
47 | { | ||
48 | int rc = 0; | ||
49 | |||
50 | card->options.large_send = type; | ||
51 | if (card->dev == NULL) | ||
52 | return 0; | ||
53 | |||
54 | if (card->options.large_send == QETH_LARGE_SEND_TSO) { | ||
55 | if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { | ||
56 | card->dev->features |= NETIF_F_TSO | NETIF_F_SG | | ||
57 | NETIF_F_HW_CSUM; | ||
58 | } else { | ||
59 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | | ||
60 | NETIF_F_HW_CSUM); | ||
61 | card->options.large_send = QETH_LARGE_SEND_NO; | ||
62 | rc = -EOPNOTSUPP; | ||
63 | } | ||
64 | } else { | ||
65 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | | ||
66 | NETIF_F_HW_CSUM); | ||
67 | card->options.large_send = QETH_LARGE_SEND_NO; | ||
68 | } | ||
69 | return rc; | ||
70 | } | ||
44 | 71 | ||
45 | static int qeth_l3_isxdigit(char *buf) | 72 | static int qeth_l3_isxdigit(char *buf) |
46 | { | 73 | { |
@@ -216,6 +243,8 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card, | |||
216 | struct qeth_ipaddr *tmp, *t; | 243 | struct qeth_ipaddr *tmp, *t; |
217 | int found = 0; | 244 | int found = 0; |
218 | 245 | ||
246 | if (card->options.sniffer) | ||
247 | return 0; | ||
219 | list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) { | 248 | list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) { |
220 | if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && | 249 | if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && |
221 | (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) | 250 | (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) |
@@ -431,6 +460,8 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) | |||
431 | QETH_DBF_TEXT(TRACE, 2, "sdiplist"); | 460 | QETH_DBF_TEXT(TRACE, 2, "sdiplist"); |
432 | QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *)); | 461 | QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *)); |
433 | 462 | ||
463 | if (card->options.sniffer) | ||
464 | return; | ||
434 | spin_lock_irqsave(&card->ip_lock, flags); | 465 | spin_lock_irqsave(&card->ip_lock, flags); |
435 | tbd_list = card->ip_tbd_list; | 466 | tbd_list = card->ip_tbd_list; |
436 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); | 467 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); |
@@ -469,7 +500,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) | |||
469 | spin_unlock_irqrestore(&card->ip_lock, flags); | 500 | spin_unlock_irqrestore(&card->ip_lock, flags); |
470 | rc = qeth_l3_deregister_addr_entry(card, addr); | 501 | rc = qeth_l3_deregister_addr_entry(card, addr); |
471 | spin_lock_irqsave(&card->ip_lock, flags); | 502 | spin_lock_irqsave(&card->ip_lock, flags); |
472 | if (!rc || (rc == IPA_RC_PRIMARY_ALREADY_DEFINED)) | 503 | if (!rc || (rc == IPA_RC_IP_ADDRESS_NOT_DEFINED)) |
473 | kfree(addr); | 504 | kfree(addr); |
474 | else | 505 | else |
475 | list_add_tail(&addr->entry, &card->ip_list); | 506 | list_add_tail(&addr->entry, &card->ip_list); |
@@ -487,6 +518,8 @@ static void qeth_l3_clear_ip_list(struct qeth_card *card, int clean, | |||
487 | unsigned long flags; | 518 | unsigned long flags; |
488 | 519 | ||
489 | QETH_DBF_TEXT(TRACE, 4, "clearip"); | 520 | QETH_DBF_TEXT(TRACE, 4, "clearip"); |
521 | if (recover && card->options.sniffer) | ||
522 | return; | ||
490 | spin_lock_irqsave(&card->ip_lock, flags); | 523 | spin_lock_irqsave(&card->ip_lock, flags); |
491 | /* clear todo list */ | 524 | /* clear todo list */ |
492 | list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) { | 525 | list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) { |
@@ -1439,6 +1472,35 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card) | |||
1439 | return 0; | 1472 | return 0; |
1440 | } | 1473 | } |
1441 | 1474 | ||
1475 | int qeth_l3_set_rx_csum(struct qeth_card *card, | ||
1476 | enum qeth_checksum_types csum_type) | ||
1477 | { | ||
1478 | int rc = 0; | ||
1479 | |||
1480 | if (card->options.checksum_type == HW_CHECKSUMMING) { | ||
1481 | if ((csum_type != HW_CHECKSUMMING) && | ||
1482 | (card->state != CARD_STATE_DOWN)) { | ||
1483 | rc = qeth_l3_send_simple_setassparms(card, | ||
1484 | IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); | ||
1485 | if (rc) | ||
1486 | return -EIO; | ||
1487 | } | ||
1488 | } else { | ||
1489 | if (csum_type == HW_CHECKSUMMING) { | ||
1490 | if (card->state != CARD_STATE_DOWN) { | ||
1491 | if (!qeth_is_supported(card, | ||
1492 | IPA_INBOUND_CHECKSUM)) | ||
1493 | return -EPERM; | ||
1494 | rc = qeth_l3_send_checksum_command(card); | ||
1495 | if (rc) | ||
1496 | return -EIO; | ||
1497 | } | ||
1498 | } | ||
1499 | } | ||
1500 | card->options.checksum_type = csum_type; | ||
1501 | return rc; | ||
1502 | } | ||
1503 | |||
1442 | static int qeth_l3_start_ipa_checksum(struct qeth_card *card) | 1504 | static int qeth_l3_start_ipa_checksum(struct qeth_card *card) |
1443 | { | 1505 | { |
1444 | int rc = 0; | 1506 | int rc = 0; |
@@ -1506,6 +1568,8 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card) | |||
1506 | static int qeth_l3_start_ipassists(struct qeth_card *card) | 1568 | static int qeth_l3_start_ipassists(struct qeth_card *card) |
1507 | { | 1569 | { |
1508 | QETH_DBF_TEXT(TRACE, 3, "strtipas"); | 1570 | QETH_DBF_TEXT(TRACE, 3, "strtipas"); |
1571 | |||
1572 | qeth_set_access_ctrl_online(card); /* go on*/ | ||
1509 | qeth_l3_start_ipa_arp_processing(card); /* go on*/ | 1573 | qeth_l3_start_ipa_arp_processing(card); /* go on*/ |
1510 | qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/ | 1574 | qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/ |
1511 | qeth_l3_start_ipa_source_mac(card); /* go on*/ | 1575 | qeth_l3_start_ipa_source_mac(card); /* go on*/ |
@@ -1617,6 +1681,80 @@ static int qeth_l3_get_unique_id(struct qeth_card *card) | |||
1617 | return rc; | 1681 | return rc; |
1618 | } | 1682 | } |
1619 | 1683 | ||
1684 | static int | ||
1685 | qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply, | ||
1686 | unsigned long data) | ||
1687 | { | ||
1688 | struct qeth_ipa_cmd *cmd; | ||
1689 | __u16 rc; | ||
1690 | |||
1691 | QETH_DBF_TEXT(SETUP, 2, "diastrcb"); | ||
1692 | |||
1693 | cmd = (struct qeth_ipa_cmd *)data; | ||
1694 | rc = cmd->hdr.return_code; | ||
1695 | if (rc) | ||
1696 | QETH_DBF_TEXT_(TRACE, 2, "dxter%x", rc); | ||
1697 | switch (cmd->data.diagass.action) { | ||
1698 | case QETH_DIAGS_CMD_TRACE_QUERY: | ||
1699 | break; | ||
1700 | case QETH_DIAGS_CMD_TRACE_DISABLE: | ||
1701 | switch (rc) { | ||
1702 | case 0: | ||
1703 | case IPA_RC_INVALID_SUBCMD: | ||
1704 | card->info.promisc_mode = SET_PROMISC_MODE_OFF; | ||
1705 | dev_info(&card->gdev->dev, "The HiperSockets network " | ||
1706 | "traffic analyzer is deactivated\n"); | ||
1707 | break; | ||
1708 | default: | ||
1709 | break; | ||
1710 | } | ||
1711 | break; | ||
1712 | case QETH_DIAGS_CMD_TRACE_ENABLE: | ||
1713 | switch (rc) { | ||
1714 | case 0: | ||
1715 | card->info.promisc_mode = SET_PROMISC_MODE_ON; | ||
1716 | dev_info(&card->gdev->dev, "The HiperSockets network " | ||
1717 | "traffic analyzer is activated\n"); | ||
1718 | break; | ||
1719 | case IPA_RC_HARDWARE_AUTH_ERROR: | ||
1720 | dev_warn(&card->gdev->dev, "The device is not " | ||
1721 | "authorized to run as a HiperSockets network " | ||
1722 | "traffic analyzer\n"); | ||
1723 | break; | ||
1724 | case IPA_RC_TRACE_ALREADY_ACTIVE: | ||
1725 | dev_warn(&card->gdev->dev, "A HiperSockets " | ||
1726 | "network traffic analyzer is already " | ||
1727 | "active in the HiperSockets LAN\n"); | ||
1728 | break; | ||
1729 | default: | ||
1730 | break; | ||
1731 | } | ||
1732 | break; | ||
1733 | default: | ||
1734 | QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n", | ||
1735 | cmd->data.diagass.action, QETH_CARD_IFNAME(card)); | ||
1736 | } | ||
1737 | |||
1738 | return 0; | ||
1739 | } | ||
1740 | |||
1741 | static int | ||
1742 | qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd) | ||
1743 | { | ||
1744 | struct qeth_cmd_buffer *iob; | ||
1745 | struct qeth_ipa_cmd *cmd; | ||
1746 | |||
1747 | QETH_DBF_TEXT(SETUP, 2, "diagtrac"); | ||
1748 | |||
1749 | iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); | ||
1750 | cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); | ||
1751 | cmd->data.diagass.subcmd_len = 16; | ||
1752 | cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE; | ||
1753 | cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET; | ||
1754 | cmd->data.diagass.action = diags_cmd; | ||
1755 | return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL); | ||
1756 | } | ||
1757 | |||
1620 | static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac, | 1758 | static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac, |
1621 | struct net_device *dev) | 1759 | struct net_device *dev) |
1622 | { | 1760 | { |
@@ -1894,7 +2032,10 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, | |||
1894 | case QETH_CAST_ANYCAST: | 2032 | case QETH_CAST_ANYCAST: |
1895 | case QETH_CAST_NOCAST: | 2033 | case QETH_CAST_NOCAST: |
1896 | default: | 2034 | default: |
1897 | skb->pkt_type = PACKET_HOST; | 2035 | if (card->options.sniffer) |
2036 | skb->pkt_type = PACKET_OTHERHOST; | ||
2037 | else | ||
2038 | skb->pkt_type = PACKET_HOST; | ||
1898 | memcpy(tg_addr, card->dev->dev_addr, | 2039 | memcpy(tg_addr, card->dev->dev_addr, |
1899 | card->dev->addr_len); | 2040 | card->dev->addr_len); |
1900 | } | 2041 | } |
@@ -1950,7 +2091,6 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
1950 | int offset; | 2091 | int offset; |
1951 | __u16 vlan_tag = 0; | 2092 | __u16 vlan_tag = 0; |
1952 | unsigned int len; | 2093 | unsigned int len; |
1953 | |||
1954 | /* get first element of current buffer */ | 2094 | /* get first element of current buffer */ |
1955 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; | 2095 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; |
1956 | offset = 0; | 2096 | offset = 0; |
@@ -1969,7 +2109,7 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
1969 | case QETH_HEADER_TYPE_LAYER3: | 2109 | case QETH_HEADER_TYPE_LAYER3: |
1970 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); | 2110 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); |
1971 | len = skb->len; | 2111 | len = skb->len; |
1972 | if (vlan_tag) | 2112 | if (vlan_tag && !card->options.sniffer) |
1973 | if (card->vlangrp) | 2113 | if (card->vlangrp) |
1974 | vlan_hwaccel_rx(skb, card->vlangrp, | 2114 | vlan_hwaccel_rx(skb, card->vlangrp, |
1975 | vlan_tag); | 2115 | vlan_tag); |
@@ -1980,6 +2120,16 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
1980 | else | 2120 | else |
1981 | netif_rx(skb); | 2121 | netif_rx(skb); |
1982 | break; | 2122 | break; |
2123 | case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ | ||
2124 | skb->pkt_type = PACKET_HOST; | ||
2125 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
2126 | if (card->options.checksum_type == NO_CHECKSUMMING) | ||
2127 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
2128 | else | ||
2129 | skb->ip_summed = CHECKSUM_NONE; | ||
2130 | len = skb->len; | ||
2131 | netif_receive_skb(skb); | ||
2132 | break; | ||
1983 | default: | 2133 | default: |
1984 | dev_kfree_skb_any(skb); | 2134 | dev_kfree_skb_any(skb); |
1985 | QETH_DBF_TEXT(TRACE, 3, "inbunkno"); | 2135 | QETH_DBF_TEXT(TRACE, 3, "inbunkno"); |
@@ -2061,17 +2211,18 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) | |||
2061 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 2211 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
2062 | 2212 | ||
2063 | qeth_set_allowed_threads(card, 0, 1); | 2213 | qeth_set_allowed_threads(card, 0, 1); |
2214 | if (card->options.sniffer && | ||
2215 | (card->info.promisc_mode == SET_PROMISC_MODE_ON)) | ||
2216 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); | ||
2064 | if (card->read.state == CH_STATE_UP && | 2217 | if (card->read.state == CH_STATE_UP && |
2065 | card->write.state == CH_STATE_UP && | 2218 | card->write.state == CH_STATE_UP && |
2066 | (card->state == CARD_STATE_UP)) { | 2219 | (card->state == CARD_STATE_UP)) { |
2067 | if (recovery_mode) | 2220 | if (recovery_mode) |
2068 | qeth_l3_stop(card->dev); | 2221 | qeth_l3_stop(card->dev); |
2069 | else { | 2222 | else { |
2070 | if (card->dev) { | 2223 | rtnl_lock(); |
2071 | rtnl_lock(); | 2224 | dev_close(card->dev); |
2072 | dev_close(card->dev); | 2225 | rtnl_unlock(); |
2073 | rtnl_unlock(); | ||
2074 | } | ||
2075 | } | 2226 | } |
2076 | if (!card->use_hard_stop) { | 2227 | if (!card->use_hard_stop) { |
2077 | rc = qeth_send_stoplan(card); | 2228 | rc = qeth_send_stoplan(card); |
@@ -2105,6 +2256,36 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) | |||
2105 | return rc; | 2256 | return rc; |
2106 | } | 2257 | } |
2107 | 2258 | ||
2259 | /* | ||
2260 | * test for and Switch promiscuous mode (on or off) | ||
2261 | * either for guestlan or HiperSocket Sniffer | ||
2262 | */ | ||
2263 | static void | ||
2264 | qeth_l3_handle_promisc_mode(struct qeth_card *card) | ||
2265 | { | ||
2266 | struct net_device *dev = card->dev; | ||
2267 | |||
2268 | if (((dev->flags & IFF_PROMISC) && | ||
2269 | (card->info.promisc_mode == SET_PROMISC_MODE_ON)) || | ||
2270 | (!(dev->flags & IFF_PROMISC) && | ||
2271 | (card->info.promisc_mode == SET_PROMISC_MODE_OFF))) | ||
2272 | return; | ||
2273 | |||
2274 | if (card->info.guestlan) { /* Guestlan trace */ | ||
2275 | if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) | ||
2276 | qeth_setadp_promisc_mode(card); | ||
2277 | } else if (card->options.sniffer && /* HiperSockets trace */ | ||
2278 | qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) { | ||
2279 | if (dev->flags & IFF_PROMISC) { | ||
2280 | QETH_DBF_TEXT(TRACE, 3, "+promisc"); | ||
2281 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE); | ||
2282 | } else { | ||
2283 | QETH_DBF_TEXT(TRACE, 3, "-promisc"); | ||
2284 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); | ||
2285 | } | ||
2286 | } | ||
2287 | } | ||
2288 | |||
2108 | static void qeth_l3_set_multicast_list(struct net_device *dev) | 2289 | static void qeth_l3_set_multicast_list(struct net_device *dev) |
2109 | { | 2290 | { |
2110 | struct qeth_card *card = dev->ml_priv; | 2291 | struct qeth_card *card = dev->ml_priv; |
@@ -2113,15 +2294,17 @@ static void qeth_l3_set_multicast_list(struct net_device *dev) | |||
2113 | if (qeth_threads_running(card, QETH_RECOVER_THREAD) && | 2294 | if (qeth_threads_running(card, QETH_RECOVER_THREAD) && |
2114 | (card->state != CARD_STATE_UP)) | 2295 | (card->state != CARD_STATE_UP)) |
2115 | return; | 2296 | return; |
2116 | qeth_l3_delete_mc_addresses(card); | 2297 | if (!card->options.sniffer) { |
2117 | qeth_l3_add_multicast_ipv4(card); | 2298 | qeth_l3_delete_mc_addresses(card); |
2299 | qeth_l3_add_multicast_ipv4(card); | ||
2118 | #ifdef CONFIG_QETH_IPV6 | 2300 | #ifdef CONFIG_QETH_IPV6 |
2119 | qeth_l3_add_multicast_ipv6(card); | 2301 | qeth_l3_add_multicast_ipv6(card); |
2120 | #endif | 2302 | #endif |
2121 | qeth_l3_set_ip_addr_list(card); | 2303 | qeth_l3_set_ip_addr_list(card); |
2122 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) | 2304 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) |
2123 | return; | 2305 | return; |
2124 | qeth_setadp_promisc_mode(card); | 2306 | } |
2307 | qeth_l3_handle_promisc_mode(card); | ||
2125 | } | 2308 | } |
2126 | 2309 | ||
2127 | static const char *qeth_l3_arp_get_error_cause(int *rc) | 2310 | static const char *qeth_l3_arp_get_error_cause(int *rc) |
@@ -2684,6 +2867,24 @@ static void qeth_tx_csum(struct sk_buff *skb) | |||
2684 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | 2867 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); |
2685 | } | 2868 | } |
2686 | 2869 | ||
2870 | static inline int qeth_l3_tso_elements(struct sk_buff *skb) | ||
2871 | { | ||
2872 | unsigned long tcpd = (unsigned long)tcp_hdr(skb) + | ||
2873 | tcp_hdr(skb)->doff * 4; | ||
2874 | int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data); | ||
2875 | int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd); | ||
2876 | elements += skb_shinfo(skb)->nr_frags; | ||
2877 | return elements; | ||
2878 | } | ||
2879 | |||
2880 | static inline int qeth_l3_tso_check(struct sk_buff *skb) | ||
2881 | { | ||
2882 | int len = ((unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4) - | ||
2883 | (unsigned long)skb->data; | ||
2884 | return (((unsigned long)skb->data & PAGE_MASK) != | ||
2885 | (((unsigned long)skb->data + len) & PAGE_MASK)); | ||
2886 | } | ||
2887 | |||
2687 | static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | 2888 | static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) |
2688 | { | 2889 | { |
2689 | int rc; | 2890 | int rc; |
@@ -2702,9 +2903,8 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2702 | int data_offset = -1; | 2903 | int data_offset = -1; |
2703 | int nr_frags; | 2904 | int nr_frags; |
2704 | 2905 | ||
2705 | if ((card->info.type == QETH_CARD_TYPE_IQD) && | 2906 | if (((card->info.type == QETH_CARD_TYPE_IQD) && (!ipv)) || |
2706 | (skb->protocol != htons(ETH_P_IPV6)) && | 2907 | card->options.sniffer) |
2707 | (skb->protocol != htons(ETH_P_IP))) | ||
2708 | goto tx_drop; | 2908 | goto tx_drop; |
2709 | 2909 | ||
2710 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { | 2910 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { |
@@ -2750,14 +2950,14 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2750 | if (data_offset < 0) | 2950 | if (data_offset < 0) |
2751 | skb_pull(new_skb, ETH_HLEN); | 2951 | skb_pull(new_skb, ETH_HLEN); |
2752 | } else { | 2952 | } else { |
2753 | if (new_skb->protocol == htons(ETH_P_IP)) { | 2953 | if (ipv == 4) { |
2754 | if (card->dev->type == ARPHRD_IEEE802_TR) | 2954 | if (card->dev->type == ARPHRD_IEEE802_TR) |
2755 | skb_pull(new_skb, TR_HLEN); | 2955 | skb_pull(new_skb, TR_HLEN); |
2756 | else | 2956 | else |
2757 | skb_pull(new_skb, ETH_HLEN); | 2957 | skb_pull(new_skb, ETH_HLEN); |
2758 | } | 2958 | } |
2759 | 2959 | ||
2760 | if (new_skb->protocol == ETH_P_IPV6 && card->vlangrp && | 2960 | if (ipv == 6 && card->vlangrp && |
2761 | vlan_tx_tag_present(new_skb)) { | 2961 | vlan_tx_tag_present(new_skb)) { |
2762 | skb_push(new_skb, VLAN_HLEN); | 2962 | skb_push(new_skb, VLAN_HLEN); |
2763 | skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4); | 2963 | skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4); |
@@ -2777,16 +2977,21 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2777 | /* fix hardware limitation: as long as we do not have sbal | 2977 | /* fix hardware limitation: as long as we do not have sbal |
2778 | * chaining we can not send long frag lists | 2978 | * chaining we can not send long frag lists |
2779 | */ | 2979 | */ |
2780 | if ((large_send == QETH_LARGE_SEND_TSO) && | 2980 | if (large_send == QETH_LARGE_SEND_TSO) { |
2781 | ((skb_shinfo(new_skb)->nr_frags + 2) > 16)) { | 2981 | if (qeth_l3_tso_elements(new_skb) + 1 > 16) { |
2782 | if (skb_linearize(new_skb)) | 2982 | if (skb_linearize(new_skb)) |
2783 | goto tx_drop; | 2983 | goto tx_drop; |
2984 | if (card->options.performance_stats) | ||
2985 | card->perf_stats.tx_lin++; | ||
2986 | } | ||
2784 | } | 2987 | } |
2785 | 2988 | ||
2786 | if ((large_send == QETH_LARGE_SEND_TSO) && | 2989 | if ((large_send == QETH_LARGE_SEND_TSO) && |
2787 | (cast_type == RTN_UNSPEC)) { | 2990 | (cast_type == RTN_UNSPEC)) { |
2788 | hdr = (struct qeth_hdr *)skb_push(new_skb, | 2991 | hdr = (struct qeth_hdr *)skb_push(new_skb, |
2789 | sizeof(struct qeth_hdr_tso)); | 2992 | sizeof(struct qeth_hdr_tso)); |
2993 | if (qeth_l3_tso_check(new_skb)) | ||
2994 | QETH_DBF_MESSAGE(2, "tso skb misaligned\n"); | ||
2790 | memset(hdr, 0, sizeof(struct qeth_hdr_tso)); | 2995 | memset(hdr, 0, sizeof(struct qeth_hdr_tso)); |
2791 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); | 2996 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); |
2792 | qeth_tso_fill_header(card, hdr, new_skb); | 2997 | qeth_tso_fill_header(card, hdr, new_skb); |
@@ -2903,46 +3108,28 @@ static u32 qeth_l3_ethtool_get_rx_csum(struct net_device *dev) | |||
2903 | static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) | 3108 | static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) |
2904 | { | 3109 | { |
2905 | struct qeth_card *card = dev->ml_priv; | 3110 | struct qeth_card *card = dev->ml_priv; |
2906 | enum qeth_card_states old_state; | ||
2907 | enum qeth_checksum_types csum_type; | 3111 | enum qeth_checksum_types csum_type; |
2908 | 3112 | ||
2909 | if ((card->state != CARD_STATE_UP) && | ||
2910 | (card->state != CARD_STATE_DOWN)) | ||
2911 | return -EPERM; | ||
2912 | |||
2913 | if (data) | 3113 | if (data) |
2914 | csum_type = HW_CHECKSUMMING; | 3114 | csum_type = HW_CHECKSUMMING; |
2915 | else | 3115 | else |
2916 | csum_type = SW_CHECKSUMMING; | 3116 | csum_type = SW_CHECKSUMMING; |
2917 | 3117 | ||
2918 | if (card->options.checksum_type != csum_type) { | 3118 | return qeth_l3_set_rx_csum(card, csum_type); |
2919 | old_state = card->state; | ||
2920 | if (card->state == CARD_STATE_UP) | ||
2921 | __qeth_l3_set_offline(card->gdev, 1); | ||
2922 | card->options.checksum_type = csum_type; | ||
2923 | if (old_state == CARD_STATE_UP) | ||
2924 | __qeth_l3_set_online(card->gdev, 1); | ||
2925 | } | ||
2926 | return 0; | ||
2927 | } | 3119 | } |
2928 | 3120 | ||
2929 | static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) | 3121 | static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) |
2930 | { | 3122 | { |
2931 | struct qeth_card *card = dev->ml_priv; | 3123 | struct qeth_card *card = dev->ml_priv; |
3124 | int rc = 0; | ||
2932 | 3125 | ||
2933 | if (data) { | 3126 | if (data) { |
2934 | if (card->options.large_send == QETH_LARGE_SEND_NO) { | 3127 | rc = qeth_l3_set_large_send(card, QETH_LARGE_SEND_TSO); |
2935 | if (card->info.type == QETH_CARD_TYPE_IQD) | ||
2936 | return -EPERM; | ||
2937 | else | ||
2938 | card->options.large_send = QETH_LARGE_SEND_TSO; | ||
2939 | dev->features |= NETIF_F_TSO; | ||
2940 | } | ||
2941 | } else { | 3128 | } else { |
2942 | dev->features &= ~NETIF_F_TSO; | 3129 | dev->features &= ~NETIF_F_TSO; |
2943 | card->options.large_send = QETH_LARGE_SEND_NO; | 3130 | card->options.large_send = QETH_LARGE_SEND_NO; |
2944 | } | 3131 | } |
2945 | return 0; | 3132 | return rc; |
2946 | } | 3133 | } |
2947 | 3134 | ||
2948 | static const struct ethtool_ops qeth_l3_ethtool_ops = { | 3135 | static const struct ethtool_ops qeth_l3_ethtool_ops = { |
@@ -2957,7 +3144,7 @@ static const struct ethtool_ops qeth_l3_ethtool_ops = { | |||
2957 | .set_tso = qeth_l3_ethtool_set_tso, | 3144 | .set_tso = qeth_l3_ethtool_set_tso, |
2958 | .get_strings = qeth_core_get_strings, | 3145 | .get_strings = qeth_core_get_strings, |
2959 | .get_ethtool_stats = qeth_core_get_ethtool_stats, | 3146 | .get_ethtool_stats = qeth_core_get_ethtool_stats, |
2960 | .get_stats_count = qeth_core_get_stats_count, | 3147 | .get_sset_count = qeth_core_get_sset_count, |
2961 | .get_drvinfo = qeth_core_get_drvinfo, | 3148 | .get_drvinfo = qeth_core_get_drvinfo, |
2962 | .get_settings = qeth_core_ethtool_get_settings, | 3149 | .get_settings = qeth_core_ethtool_get_settings, |
2963 | }; | 3150 | }; |
@@ -3058,6 +3245,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) | |||
3058 | NETIF_F_HW_VLAN_RX | | 3245 | NETIF_F_HW_VLAN_RX | |
3059 | NETIF_F_HW_VLAN_FILTER; | 3246 | NETIF_F_HW_VLAN_FILTER; |
3060 | card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | 3247 | card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; |
3248 | card->dev->gso_max_size = 15 * PAGE_SIZE; | ||
3061 | 3249 | ||
3062 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); | 3250 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); |
3063 | return register_netdev(card->dev); | 3251 | return register_netdev(card->dev); |
@@ -3092,7 +3280,7 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev, | |||
3092 | index = i % QDIO_MAX_BUFFERS_PER_Q; | 3280 | index = i % QDIO_MAX_BUFFERS_PER_Q; |
3093 | buffer = &card->qdio.in_q->bufs[index]; | 3281 | buffer = &card->qdio.in_q->bufs[index]; |
3094 | if (!(qdio_err && | 3282 | if (!(qdio_err && |
3095 | qeth_check_qdio_errors(buffer->buffer, | 3283 | qeth_check_qdio_errors(card, buffer->buffer, |
3096 | qdio_err, "qinerr"))) | 3284 | qdio_err, "qinerr"))) |
3097 | qeth_l3_process_inbound_buffer(card, buffer, index); | 3285 | qeth_l3_process_inbound_buffer(card, buffer, index); |
3098 | /* clear buffer and give back to hardware */ | 3286 | /* clear buffer and give back to hardware */ |
@@ -3151,35 +3339,20 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3151 | QETH_DBF_TEXT(SETUP, 2, "setonlin"); | 3339 | QETH_DBF_TEXT(SETUP, 2, "setonlin"); |
3152 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 3340 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
3153 | 3341 | ||
3154 | qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); | ||
3155 | |||
3156 | recover_flag = card->state; | 3342 | recover_flag = card->state; |
3157 | rc = ccw_device_set_online(CARD_RDEV(card)); | ||
3158 | if (rc) { | ||
3159 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
3160 | return -EIO; | ||
3161 | } | ||
3162 | rc = ccw_device_set_online(CARD_WDEV(card)); | ||
3163 | if (rc) { | ||
3164 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
3165 | return -EIO; | ||
3166 | } | ||
3167 | rc = ccw_device_set_online(CARD_DDEV(card)); | ||
3168 | if (rc) { | ||
3169 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
3170 | return -EIO; | ||
3171 | } | ||
3172 | |||
3173 | rc = qeth_core_hardsetup_card(card); | 3343 | rc = qeth_core_hardsetup_card(card); |
3174 | if (rc) { | 3344 | if (rc) { |
3175 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | 3345 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); |
3346 | rc = -ENODEV; | ||
3176 | goto out_remove; | 3347 | goto out_remove; |
3177 | } | 3348 | } |
3178 | 3349 | ||
3179 | qeth_l3_query_ipassists(card, QETH_PROT_IPV4); | 3350 | qeth_l3_query_ipassists(card, QETH_PROT_IPV4); |
3180 | 3351 | ||
3181 | if (!card->dev && qeth_l3_setup_netdev(card)) | 3352 | if (!card->dev && qeth_l3_setup_netdev(card)) { |
3353 | rc = -ENODEV; | ||
3182 | goto out_remove; | 3354 | goto out_remove; |
3355 | } | ||
3183 | 3356 | ||
3184 | card->state = CARD_STATE_HARDSETUP; | 3357 | card->state = CARD_STATE_HARDSETUP; |
3185 | qeth_print_status_message(card); | 3358 | qeth_print_status_message(card); |
@@ -3196,28 +3369,32 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3196 | card->lan_online = 0; | 3369 | card->lan_online = 0; |
3197 | return 0; | 3370 | return 0; |
3198 | } | 3371 | } |
3372 | rc = -ENODEV; | ||
3199 | goto out_remove; | 3373 | goto out_remove; |
3200 | } else | 3374 | } else |
3201 | card->lan_online = 1; | 3375 | card->lan_online = 1; |
3202 | qeth_set_large_send(card, card->options.large_send); | ||
3203 | 3376 | ||
3204 | rc = qeth_l3_setadapter_parms(card); | 3377 | rc = qeth_l3_setadapter_parms(card); |
3205 | if (rc) | 3378 | if (rc) |
3206 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | 3379 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); |
3207 | rc = qeth_l3_start_ipassists(card); | 3380 | if (!card->options.sniffer) { |
3208 | if (rc) | 3381 | rc = qeth_l3_start_ipassists(card); |
3209 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); | 3382 | if (rc) |
3210 | rc = qeth_l3_setrouting_v4(card); | 3383 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); |
3211 | if (rc) | 3384 | qeth_l3_set_large_send(card, card->options.large_send); |
3212 | QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); | 3385 | rc = qeth_l3_setrouting_v4(card); |
3213 | rc = qeth_l3_setrouting_v6(card); | 3386 | if (rc) |
3214 | if (rc) | 3387 | QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); |
3215 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | 3388 | rc = qeth_l3_setrouting_v6(card); |
3389 | if (rc) | ||
3390 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | ||
3391 | } | ||
3216 | netif_tx_disable(card->dev); | 3392 | netif_tx_disable(card->dev); |
3217 | 3393 | ||
3218 | rc = qeth_init_qdio_queues(card); | 3394 | rc = qeth_init_qdio_queues(card); |
3219 | if (rc) { | 3395 | if (rc) { |
3220 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); | 3396 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); |
3397 | rc = -ENODEV; | ||
3221 | goto out_remove; | 3398 | goto out_remove; |
3222 | } | 3399 | } |
3223 | card->state = CARD_STATE_SOFTSETUP; | 3400 | card->state = CARD_STATE_SOFTSETUP; |
@@ -3248,7 +3425,7 @@ out_remove: | |||
3248 | card->state = CARD_STATE_RECOVER; | 3425 | card->state = CARD_STATE_RECOVER; |
3249 | else | 3426 | else |
3250 | card->state = CARD_STATE_DOWN; | 3427 | card->state = CARD_STATE_DOWN; |
3251 | return -ENODEV; | 3428 | return rc; |
3252 | } | 3429 | } |
3253 | 3430 | ||
3254 | static int qeth_l3_set_online(struct ccwgroup_device *gdev) | 3431 | static int qeth_l3_set_online(struct ccwgroup_device *gdev) |
@@ -3358,11 +3535,9 @@ static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) | |||
3358 | if (card->state == CARD_STATE_RECOVER) { | 3535 | if (card->state == CARD_STATE_RECOVER) { |
3359 | rc = __qeth_l3_set_online(card->gdev, 1); | 3536 | rc = __qeth_l3_set_online(card->gdev, 1); |
3360 | if (rc) { | 3537 | if (rc) { |
3361 | if (card->dev) { | 3538 | rtnl_lock(); |
3362 | rtnl_lock(); | 3539 | dev_close(card->dev); |
3363 | dev_close(card->dev); | 3540 | rtnl_unlock(); |
3364 | rtnl_unlock(); | ||
3365 | } | ||
3366 | } | 3541 | } |
3367 | } else | 3542 | } else |
3368 | rc = __qeth_l3_set_online(card->gdev, 0); | 3543 | rc = __qeth_l3_set_online(card->gdev, 0); |