diff options
Diffstat (limited to 'drivers/s390/net/qeth_main.c')
-rw-r--r-- | drivers/s390/net/qeth_main.c | 316 |
1 files changed, 213 insertions, 103 deletions
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 607b92542df6..208127a5033a 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * linux/drivers/s390/net/qeth_main.c ($Revision: 1.206 $) | 3 | * linux/drivers/s390/net/qeth_main.c ($Revision: 1.214 $) |
4 | * | 4 | * |
5 | * Linux on zSeries OSA Express and HiperSockets support | 5 | * Linux on zSeries OSA Express and HiperSockets support |
6 | * | 6 | * |
@@ -12,7 +12,7 @@ | |||
12 | * Frank Pavlic (pavlic@de.ibm.com) and | 12 | * Frank Pavlic (pavlic@de.ibm.com) and |
13 | * Thomas Spatzier <tspat@de.ibm.com> | 13 | * Thomas Spatzier <tspat@de.ibm.com> |
14 | * | 14 | * |
15 | * $Revision: 1.206 $ $Date: 2005/03/24 09:04:18 $ | 15 | * $Revision: 1.214 $ $Date: 2005/05/04 20:19:18 $ |
16 | * | 16 | * |
17 | * This program is free software; you can redistribute it and/or modify | 17 | * This program is free software; you can redistribute it and/or modify |
18 | * it under the terms of the GNU General Public License as published by | 18 | * it under the terms of the GNU General Public License as published by |
@@ -80,7 +80,7 @@ qeth_eyecatcher(void) | |||
80 | #include "qeth_eddp.h" | 80 | #include "qeth_eddp.h" |
81 | #include "qeth_tso.h" | 81 | #include "qeth_tso.h" |
82 | 82 | ||
83 | #define VERSION_QETH_C "$Revision: 1.206 $" | 83 | #define VERSION_QETH_C "$Revision: 1.214 $" |
84 | static const char *version = "qeth S/390 OSA-Express driver"; | 84 | static const char *version = "qeth S/390 OSA-Express driver"; |
85 | 85 | ||
86 | /** | 86 | /** |
@@ -158,6 +158,9 @@ qeth_irq_tasklet(unsigned long); | |||
158 | static int | 158 | static int |
159 | qeth_set_online(struct ccwgroup_device *); | 159 | qeth_set_online(struct ccwgroup_device *); |
160 | 160 | ||
161 | static int | ||
162 | __qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode); | ||
163 | |||
161 | static struct qeth_ipaddr * | 164 | static struct qeth_ipaddr * |
162 | qeth_get_addr_buffer(enum qeth_prot_versions); | 165 | qeth_get_addr_buffer(enum qeth_prot_versions); |
163 | 166 | ||
@@ -510,10 +513,10 @@ qeth_irq_tasklet(unsigned long data) | |||
510 | wake_up(&card->wait_q); | 513 | wake_up(&card->wait_q); |
511 | } | 514 | } |
512 | 515 | ||
513 | static int qeth_stop_card(struct qeth_card *); | 516 | static int qeth_stop_card(struct qeth_card *, int); |
514 | 517 | ||
515 | static int | 518 | static int |
516 | qeth_set_offline(struct ccwgroup_device *cgdev) | 519 | __qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode) |
517 | { | 520 | { |
518 | struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data; | 521 | struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data; |
519 | int rc = 0; | 522 | int rc = 0; |
@@ -523,7 +526,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev) | |||
523 | QETH_DBF_HEX(setup, 3, &card, sizeof(void *)); | 526 | QETH_DBF_HEX(setup, 3, &card, sizeof(void *)); |
524 | 527 | ||
525 | recover_flag = card->state; | 528 | recover_flag = card->state; |
526 | if (qeth_stop_card(card) == -ERESTARTSYS){ | 529 | if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){ |
527 | PRINT_WARN("Stopping card %s interrupted by user!\n", | 530 | PRINT_WARN("Stopping card %s interrupted by user!\n", |
528 | CARD_BUS_ID(card)); | 531 | CARD_BUS_ID(card)); |
529 | return -ERESTARTSYS; | 532 | return -ERESTARTSYS; |
@@ -540,6 +543,12 @@ qeth_set_offline(struct ccwgroup_device *cgdev) | |||
540 | } | 543 | } |
541 | 544 | ||
542 | static int | 545 | static int |
546 | qeth_set_offline(struct ccwgroup_device *cgdev) | ||
547 | { | ||
548 | return __qeth_set_offline(cgdev, 0); | ||
549 | } | ||
550 | |||
551 | static int | ||
543 | qeth_wait_for_threads(struct qeth_card *card, unsigned long threads); | 552 | qeth_wait_for_threads(struct qeth_card *card, unsigned long threads); |
544 | 553 | ||
545 | 554 | ||
@@ -953,8 +962,8 @@ qeth_recover(void *ptr) | |||
953 | PRINT_WARN("Recovery of device %s started ...\n", | 962 | PRINT_WARN("Recovery of device %s started ...\n", |
954 | CARD_BUS_ID(card)); | 963 | CARD_BUS_ID(card)); |
955 | card->use_hard_stop = 1; | 964 | card->use_hard_stop = 1; |
956 | qeth_set_offline(card->gdev); | 965 | __qeth_set_offline(card->gdev,1); |
957 | rc = qeth_set_online(card->gdev); | 966 | rc = __qeth_set_online(card->gdev,1); |
958 | if (!rc) | 967 | if (!rc) |
959 | PRINT_INFO("Device %s successfully recovered!\n", | 968 | PRINT_INFO("Device %s successfully recovered!\n", |
960 | CARD_BUS_ID(card)); | 969 | CARD_BUS_ID(card)); |
@@ -2152,9 +2161,15 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, | |||
2152 | if (!skb_len) | 2161 | if (!skb_len) |
2153 | return NULL; | 2162 | return NULL; |
2154 | if (card->options.fake_ll){ | 2163 | if (card->options.fake_ll){ |
2155 | if (!(skb = qeth_get_skb(skb_len + QETH_FAKE_LL_LEN))) | 2164 | if(card->dev->type == ARPHRD_IEEE802_TR){ |
2156 | goto no_mem; | 2165 | if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR))) |
2157 | skb_pull(skb, QETH_FAKE_LL_LEN); | 2166 | goto no_mem; |
2167 | skb_reserve(skb,QETH_FAKE_LL_LEN_TR); | ||
2168 | } else { | ||
2169 | if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH))) | ||
2170 | goto no_mem; | ||
2171 | skb_reserve(skb,QETH_FAKE_LL_LEN_ETH); | ||
2172 | } | ||
2158 | } else if (!(skb = qeth_get_skb(skb_len))) | 2173 | } else if (!(skb = qeth_get_skb(skb_len))) |
2159 | goto no_mem; | 2174 | goto no_mem; |
2160 | data_ptr = element->addr + offset; | 2175 | data_ptr = element->addr + offset; |
@@ -2229,14 +2244,68 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev) | |||
2229 | } | 2244 | } |
2230 | 2245 | ||
2231 | static inline void | 2246 | static inline void |
2232 | qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, | 2247 | qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb, |
2248 | struct qeth_hdr *hdr) | ||
2249 | { | ||
2250 | struct trh_hdr *fake_hdr; | ||
2251 | struct trllc *fake_llc; | ||
2252 | struct iphdr *ip_hdr; | ||
2253 | |||
2254 | QETH_DBF_TEXT(trace,5,"skbfktr"); | ||
2255 | skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_TR; | ||
2256 | /* this is a fake ethernet header */ | ||
2257 | fake_hdr = (struct trh_hdr *) skb->mac.raw; | ||
2258 | |||
2259 | /* the destination MAC address */ | ||
2260 | switch (skb->pkt_type){ | ||
2261 | case PACKET_MULTICAST: | ||
2262 | switch (skb->protocol){ | ||
2263 | #ifdef CONFIG_QETH_IPV6 | ||
2264 | case __constant_htons(ETH_P_IPV6): | ||
2265 | ndisc_mc_map((struct in6_addr *) | ||
2266 | skb->data + QETH_FAKE_LL_V6_ADDR_POS, | ||
2267 | fake_hdr->daddr, card->dev, 0); | ||
2268 | break; | ||
2269 | #endif /* CONFIG_QETH_IPV6 */ | ||
2270 | case __constant_htons(ETH_P_IP): | ||
2271 | ip_hdr = (struct iphdr *)skb->data; | ||
2272 | ip_tr_mc_map(ip_hdr->daddr, fake_hdr->daddr); | ||
2273 | break; | ||
2274 | default: | ||
2275 | memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN); | ||
2276 | } | ||
2277 | break; | ||
2278 | case PACKET_BROADCAST: | ||
2279 | memset(fake_hdr->daddr, 0xff, TR_ALEN); | ||
2280 | break; | ||
2281 | default: | ||
2282 | memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN); | ||
2283 | } | ||
2284 | /* the source MAC address */ | ||
2285 | if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR) | ||
2286 | memcpy(fake_hdr->saddr, &hdr->hdr.l3.dest_addr[2], TR_ALEN); | ||
2287 | else | ||
2288 | memset(fake_hdr->saddr, 0, TR_ALEN); | ||
2289 | fake_hdr->rcf=0; | ||
2290 | fake_llc = (struct trllc*)&(fake_hdr->rcf); | ||
2291 | fake_llc->dsap = EXTENDED_SAP; | ||
2292 | fake_llc->ssap = EXTENDED_SAP; | ||
2293 | fake_llc->llc = UI_CMD; | ||
2294 | fake_llc->protid[0] = 0; | ||
2295 | fake_llc->protid[1] = 0; | ||
2296 | fake_llc->protid[2] = 0; | ||
2297 | fake_llc->ethertype = ETH_P_IP; | ||
2298 | } | ||
2299 | |||
2300 | static inline void | ||
2301 | qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb, | ||
2233 | struct qeth_hdr *hdr) | 2302 | struct qeth_hdr *hdr) |
2234 | { | 2303 | { |
2235 | struct ethhdr *fake_hdr; | 2304 | struct ethhdr *fake_hdr; |
2236 | struct iphdr *ip_hdr; | 2305 | struct iphdr *ip_hdr; |
2237 | 2306 | ||
2238 | QETH_DBF_TEXT(trace,5,"skbfake"); | 2307 | QETH_DBF_TEXT(trace,5,"skbfketh"); |
2239 | skb->mac.raw = skb->data - QETH_FAKE_LL_LEN; | 2308 | skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_ETH; |
2240 | /* this is a fake ethernet header */ | 2309 | /* this is a fake ethernet header */ |
2241 | fake_hdr = (struct ethhdr *) skb->mac.raw; | 2310 | fake_hdr = (struct ethhdr *) skb->mac.raw; |
2242 | 2311 | ||
@@ -2253,10 +2322,7 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, | |||
2253 | #endif /* CONFIG_QETH_IPV6 */ | 2322 | #endif /* CONFIG_QETH_IPV6 */ |
2254 | case __constant_htons(ETH_P_IP): | 2323 | case __constant_htons(ETH_P_IP): |
2255 | ip_hdr = (struct iphdr *)skb->data; | 2324 | ip_hdr = (struct iphdr *)skb->data; |
2256 | if (card->dev->type == ARPHRD_IEEE802_TR) | 2325 | ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest); |
2257 | ip_tr_mc_map(ip_hdr->daddr, fake_hdr->h_dest); | ||
2258 | else | ||
2259 | ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest); | ||
2260 | break; | 2326 | break; |
2261 | default: | 2327 | default: |
2262 | memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN); | 2328 | memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN); |
@@ -2278,6 +2344,16 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, | |||
2278 | } | 2344 | } |
2279 | 2345 | ||
2280 | static inline void | 2346 | static inline void |
2347 | qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, | ||
2348 | struct qeth_hdr *hdr) | ||
2349 | { | ||
2350 | if (card->dev->type == ARPHRD_IEEE802_TR) | ||
2351 | qeth_rebuild_skb_fake_ll_tr(card, skb, hdr); | ||
2352 | else | ||
2353 | qeth_rebuild_skb_fake_ll_eth(card, skb, hdr); | ||
2354 | } | ||
2355 | |||
2356 | static inline void | ||
2281 | qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb, | 2357 | qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb, |
2282 | struct qeth_hdr *hdr) | 2358 | struct qeth_hdr *hdr) |
2283 | { | 2359 | { |
@@ -3440,16 +3516,25 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev, | |||
3440 | unsigned short type, void *daddr, void *saddr, | 3516 | unsigned short type, void *daddr, void *saddr, |
3441 | unsigned len) | 3517 | unsigned len) |
3442 | { | 3518 | { |
3443 | struct ethhdr *hdr; | 3519 | if(dev->type == ARPHRD_IEEE802_TR){ |
3520 | struct trh_hdr *hdr; | ||
3521 | hdr = (struct trh_hdr *)skb_push(skb, QETH_FAKE_LL_LEN_TR); | ||
3522 | memcpy(hdr->saddr, dev->dev_addr, TR_ALEN); | ||
3523 | memcpy(hdr->daddr, "FAKELL", TR_ALEN); | ||
3524 | return QETH_FAKE_LL_LEN_TR; | ||
3525 | |||
3526 | } else { | ||
3527 | struct ethhdr *hdr; | ||
3528 | hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN_ETH); | ||
3529 | memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN); | ||
3530 | memcpy(hdr->h_dest, "FAKELL", ETH_ALEN); | ||
3531 | if (type != ETH_P_802_3) | ||
3532 | hdr->h_proto = htons(type); | ||
3533 | else | ||
3534 | hdr->h_proto = htons(len); | ||
3535 | return QETH_FAKE_LL_LEN_ETH; | ||
3444 | 3536 | ||
3445 | hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN); | 3537 | } |
3446 | memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN); | ||
3447 | memcpy(hdr->h_dest, "FAKELL", ETH_ALEN); | ||
3448 | if (type != ETH_P_802_3) | ||
3449 | hdr->h_proto = htons(type); | ||
3450 | else | ||
3451 | hdr->h_proto = htons(len); | ||
3452 | return QETH_FAKE_LL_LEN; | ||
3453 | } | 3538 | } |
3454 | 3539 | ||
3455 | static inline int | 3540 | static inline int |
@@ -3710,16 +3795,12 @@ static inline int | |||
3710 | qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, | 3795 | qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, |
3711 | struct qeth_hdr **hdr, int ipv) | 3796 | struct qeth_hdr **hdr, int ipv) |
3712 | { | 3797 | { |
3713 | int rc = 0; | ||
3714 | #ifdef CONFIG_QETH_VLAN | 3798 | #ifdef CONFIG_QETH_VLAN |
3715 | u16 *tag; | 3799 | u16 *tag; |
3716 | #endif | 3800 | #endif |
3717 | 3801 | ||
3718 | QETH_DBF_TEXT(trace, 6, "prepskb"); | 3802 | QETH_DBF_TEXT(trace, 6, "prepskb"); |
3719 | 3803 | ||
3720 | rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); | ||
3721 | if (rc) | ||
3722 | return rc; | ||
3723 | #ifdef CONFIG_QETH_VLAN | 3804 | #ifdef CONFIG_QETH_VLAN |
3724 | if (card->vlangrp && vlan_tx_tag_present(*skb) && | 3805 | if (card->vlangrp && vlan_tx_tag_present(*skb) && |
3725 | ((ipv == 6) || card->options.layer2) ) { | 3806 | ((ipv == 6) || card->options.layer2) ) { |
@@ -3882,9 +3963,15 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | |||
3882 | memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16); | 3963 | memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16); |
3883 | } | 3964 | } |
3884 | } else { /* passthrough */ | 3965 | } else { /* passthrough */ |
3885 | if (!memcmp(skb->data + sizeof(struct qeth_hdr), | 3966 | if((skb->dev->type == ARPHRD_IEEE802_TR) && |
3967 | !memcmp(skb->data + sizeof(struct qeth_hdr) + | ||
3968 | sizeof(__u16), skb->dev->broadcast, 6)) { | ||
3969 | hdr->hdr.l3.flags = QETH_CAST_BROADCAST | | ||
3970 | QETH_HDR_PASSTHRU; | ||
3971 | } else if (!memcmp(skb->data + sizeof(struct qeth_hdr), | ||
3886 | skb->dev->broadcast, 6)) { /* broadcast? */ | 3972 | skb->dev->broadcast, 6)) { /* broadcast? */ |
3887 | hdr->hdr.l3.flags = QETH_CAST_BROADCAST | QETH_HDR_PASSTHRU; | 3973 | hdr->hdr.l3.flags = QETH_CAST_BROADCAST | |
3974 | QETH_HDR_PASSTHRU; | ||
3888 | } else { | 3975 | } else { |
3889 | hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ? | 3976 | hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ? |
3890 | QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU : | 3977 | QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU : |
@@ -3894,67 +3981,29 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | |||
3894 | } | 3981 | } |
3895 | 3982 | ||
3896 | static inline void | 3983 | static inline void |
3897 | __qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer, | ||
3898 | int *next_element_to_fill) | ||
3899 | { | ||
3900 | int length = skb->len; | ||
3901 | struct skb_frag_struct *frag; | ||
3902 | int fragno; | ||
3903 | unsigned long addr; | ||
3904 | int element; | ||
3905 | int first_lap = 1; | ||
3906 | |||
3907 | fragno = skb_shinfo(skb)->nr_frags; /* start with last frag */ | ||
3908 | element = *next_element_to_fill + fragno; | ||
3909 | while (length > 0) { | ||
3910 | if (fragno > 0) { | ||
3911 | frag = &skb_shinfo(skb)->frags[fragno - 1]; | ||
3912 | addr = (page_to_pfn(frag->page) << PAGE_SHIFT) + | ||
3913 | frag->page_offset; | ||
3914 | buffer->element[element].addr = (char *)addr; | ||
3915 | buffer->element[element].length = frag->size; | ||
3916 | length -= frag->size; | ||
3917 | if (first_lap) | ||
3918 | buffer->element[element].flags = | ||
3919 | SBAL_FLAGS_LAST_FRAG; | ||
3920 | else | ||
3921 | buffer->element[element].flags = | ||
3922 | SBAL_FLAGS_MIDDLE_FRAG; | ||
3923 | } else { | ||
3924 | buffer->element[element].addr = skb->data; | ||
3925 | buffer->element[element].length = length; | ||
3926 | length = 0; | ||
3927 | buffer->element[element].flags = | ||
3928 | SBAL_FLAGS_FIRST_FRAG; | ||
3929 | } | ||
3930 | element--; | ||
3931 | fragno--; | ||
3932 | first_lap = 0; | ||
3933 | } | ||
3934 | *next_element_to_fill += skb_shinfo(skb)->nr_frags + 1; | ||
3935 | } | ||
3936 | |||
3937 | static inline void | ||
3938 | __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer, | 3984 | __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer, |
3939 | int *next_element_to_fill) | 3985 | int is_tso, int *next_element_to_fill) |
3940 | { | 3986 | { |
3941 | int length = skb->len; | 3987 | int length = skb->len; |
3942 | int length_here; | 3988 | int length_here; |
3943 | int element; | 3989 | int element; |
3944 | char *data; | 3990 | char *data; |
3945 | int first_lap = 1; | 3991 | int first_lap ; |
3946 | 3992 | ||
3947 | element = *next_element_to_fill; | 3993 | element = *next_element_to_fill; |
3948 | data = skb->data; | 3994 | data = skb->data; |
3995 | first_lap = (is_tso == 0 ? 1 : 0); | ||
3996 | |||
3949 | while (length > 0) { | 3997 | while (length > 0) { |
3950 | /* length_here is the remaining amount of data in this page */ | 3998 | /* length_here is the remaining amount of data in this page */ |
3951 | length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); | 3999 | length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); |
3952 | if (length < length_here) | 4000 | if (length < length_here) |
3953 | length_here = length; | 4001 | length_here = length; |
4002 | |||
3954 | buffer->element[element].addr = data; | 4003 | buffer->element[element].addr = data; |
3955 | buffer->element[element].length = length_here; | 4004 | buffer->element[element].length = length_here; |
3956 | length -= length_here; | 4005 | length -= length_here; |
3957 | if (!length){ | 4006 | if (!length) { |
3958 | if (first_lap) | 4007 | if (first_lap) |
3959 | buffer->element[element].flags = 0; | 4008 | buffer->element[element].flags = 0; |
3960 | else | 4009 | else |
@@ -3981,17 +4030,35 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, | |||
3981 | struct sk_buff *skb) | 4030 | struct sk_buff *skb) |
3982 | { | 4031 | { |
3983 | struct qdio_buffer *buffer; | 4032 | struct qdio_buffer *buffer; |
3984 | int flush_cnt = 0; | 4033 | struct qeth_hdr_tso *hdr; |
4034 | int flush_cnt = 0, hdr_len, large_send = 0; | ||
3985 | 4035 | ||
3986 | QETH_DBF_TEXT(trace, 6, "qdfillbf"); | 4036 | QETH_DBF_TEXT(trace, 6, "qdfillbf"); |
4037 | |||
3987 | buffer = buf->buffer; | 4038 | buffer = buf->buffer; |
3988 | atomic_inc(&skb->users); | 4039 | atomic_inc(&skb->users); |
3989 | skb_queue_tail(&buf->skb_list, skb); | 4040 | skb_queue_tail(&buf->skb_list, skb); |
4041 | |||
4042 | hdr = (struct qeth_hdr_tso *) skb->data; | ||
4043 | /*check first on TSO ....*/ | ||
4044 | if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) { | ||
4045 | int element = buf->next_element_to_fill; | ||
4046 | |||
4047 | hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len; | ||
4048 | /*fill first buffer entry only with header information */ | ||
4049 | buffer->element[element].addr = skb->data; | ||
4050 | buffer->element[element].length = hdr_len; | ||
4051 | buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG; | ||
4052 | buf->next_element_to_fill++; | ||
4053 | skb->data += hdr_len; | ||
4054 | skb->len -= hdr_len; | ||
4055 | large_send = 1; | ||
4056 | } | ||
3990 | if (skb_shinfo(skb)->nr_frags == 0) | 4057 | if (skb_shinfo(skb)->nr_frags == 0) |
3991 | __qeth_fill_buffer(skb, buffer, | 4058 | __qeth_fill_buffer(skb, buffer, large_send, |
3992 | (int *)&buf->next_element_to_fill); | 4059 | (int *)&buf->next_element_to_fill); |
3993 | else | 4060 | else |
3994 | __qeth_fill_buffer_frag(skb, buffer, | 4061 | __qeth_fill_buffer_frag(skb, buffer, large_send, |
3995 | (int *)&buf->next_element_to_fill); | 4062 | (int *)&buf->next_element_to_fill); |
3996 | 4063 | ||
3997 | if (!queue->do_pack) { | 4064 | if (!queue->do_pack) { |
@@ -4184,6 +4251,25 @@ out: | |||
4184 | } | 4251 | } |
4185 | 4252 | ||
4186 | static inline int | 4253 | static inline int |
4254 | qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb) | ||
4255 | { | ||
4256 | int elements_needed = 0; | ||
4257 | |||
4258 | if (skb_shinfo(skb)->nr_frags > 0) { | ||
4259 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); | ||
4260 | } | ||
4261 | if (elements_needed == 0 ) | ||
4262 | elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) | ||
4263 | + skb->len) >> PAGE_SHIFT); | ||
4264 | if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){ | ||
4265 | PRINT_ERR("qeth_do_send_packet: invalid size of " | ||
4266 | "IP packet. Discarded."); | ||
4267 | return 0; | ||
4268 | } | ||
4269 | return elements_needed; | ||
4270 | } | ||
4271 | |||
4272 | static inline int | ||
4187 | qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) | 4273 | qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) |
4188 | { | 4274 | { |
4189 | int ipv = 0; | 4275 | int ipv = 0; |
@@ -4205,7 +4291,11 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) | |||
4205 | dev_kfree_skb_irq(skb); | 4291 | dev_kfree_skb_irq(skb); |
4206 | return 0; | 4292 | return 0; |
4207 | } | 4293 | } |
4208 | skb_pull(skb, QETH_FAKE_LL_LEN); | 4294 | if(card->dev->type == ARPHRD_IEEE802_TR){ |
4295 | skb_pull(skb, QETH_FAKE_LL_LEN_TR); | ||
4296 | } else { | ||
4297 | skb_pull(skb, QETH_FAKE_LL_LEN_ETH); | ||
4298 | } | ||
4209 | } | 4299 | } |
4210 | } | 4300 | } |
4211 | cast_type = qeth_get_cast_type(card, skb); | 4301 | cast_type = qeth_get_cast_type(card, skb); |
@@ -4221,19 +4311,25 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) | |||
4221 | if (skb_shinfo(skb)->tso_size) | 4311 | if (skb_shinfo(skb)->tso_size) |
4222 | large_send = card->options.large_send; | 4312 | large_send = card->options.large_send; |
4223 | 4313 | ||
4224 | if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))){ | ||
4225 | QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc); | ||
4226 | return rc; | ||
4227 | } | ||
4228 | /*are we able to do TSO ? If so ,prepare and send it from here */ | 4314 | /*are we able to do TSO ? If so ,prepare and send it from here */ |
4229 | if ((large_send == QETH_LARGE_SEND_TSO) && | 4315 | if ((large_send == QETH_LARGE_SEND_TSO) && |
4230 | (cast_type == RTN_UNSPEC)) { | 4316 | (cast_type == RTN_UNSPEC)) { |
4231 | rc = qeth_tso_send_packet(card, skb, queue, | 4317 | rc = qeth_tso_prepare_packet(card, skb, ipv, cast_type); |
4232 | ipv, cast_type); | 4318 | if (rc) { |
4233 | goto do_statistics; | 4319 | card->stats.tx_dropped++; |
4320 | card->stats.tx_errors++; | ||
4321 | dev_kfree_skb_any(skb); | ||
4322 | return NETDEV_TX_OK; | ||
4323 | } | ||
4324 | elements_needed++; | ||
4325 | } else { | ||
4326 | if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) { | ||
4327 | QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc); | ||
4328 | return rc; | ||
4329 | } | ||
4330 | qeth_fill_header(card, hdr, skb, ipv, cast_type); | ||
4234 | } | 4331 | } |
4235 | 4332 | ||
4236 | qeth_fill_header(card, hdr, skb, ipv, cast_type); | ||
4237 | if (large_send == QETH_LARGE_SEND_EDDP) { | 4333 | if (large_send == QETH_LARGE_SEND_EDDP) { |
4238 | ctx = qeth_eddp_create_context(card, skb, hdr); | 4334 | ctx = qeth_eddp_create_context(card, skb, hdr); |
4239 | if (ctx == NULL) { | 4335 | if (ctx == NULL) { |
@@ -4241,7 +4337,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) | |||
4241 | return -EINVAL; | 4337 | return -EINVAL; |
4242 | } | 4338 | } |
4243 | } else { | 4339 | } else { |
4244 | elements_needed = qeth_get_elements_no(card,(void*) hdr, skb); | 4340 | elements_needed += qeth_get_elements_no(card,(void*) hdr, skb); |
4245 | if (!elements_needed) | 4341 | if (!elements_needed) |
4246 | return -EINVAL; | 4342 | return -EINVAL; |
4247 | } | 4343 | } |
@@ -4252,12 +4348,12 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) | |||
4252 | else | 4348 | else |
4253 | rc = qeth_do_send_packet_fast(card, queue, skb, hdr, | 4349 | rc = qeth_do_send_packet_fast(card, queue, skb, hdr, |
4254 | elements_needed, ctx); | 4350 | elements_needed, ctx); |
4255 | do_statistics: | ||
4256 | if (!rc){ | 4351 | if (!rc){ |
4257 | card->stats.tx_packets++; | 4352 | card->stats.tx_packets++; |
4258 | card->stats.tx_bytes += skb->len; | 4353 | card->stats.tx_bytes += skb->len; |
4259 | #ifdef CONFIG_QETH_PERF_STATS | 4354 | #ifdef CONFIG_QETH_PERF_STATS |
4260 | if (skb_shinfo(skb)->tso_size) { | 4355 | if (skb_shinfo(skb)->tso_size && |
4356 | !(large_send == QETH_LARGE_SEND_NO)) { | ||
4261 | card->perf_stats.large_send_bytes += skb->len; | 4357 | card->perf_stats.large_send_bytes += skb->len; |
4262 | card->perf_stats.large_send_cnt++; | 4358 | card->perf_stats.large_send_cnt++; |
4263 | } | 4359 | } |
@@ -7154,7 +7250,7 @@ qeth_wait_for_threads(struct qeth_card *card, unsigned long threads) | |||
7154 | } | 7250 | } |
7155 | 7251 | ||
7156 | static int | 7252 | static int |
7157 | qeth_stop_card(struct qeth_card *card) | 7253 | qeth_stop_card(struct qeth_card *card, int recovery_mode) |
7158 | { | 7254 | { |
7159 | int rc = 0; | 7255 | int rc = 0; |
7160 | 7256 | ||
@@ -7167,9 +7263,13 @@ qeth_stop_card(struct qeth_card *card) | |||
7167 | if (card->read.state == CH_STATE_UP && | 7263 | if (card->read.state == CH_STATE_UP && |
7168 | card->write.state == CH_STATE_UP && | 7264 | card->write.state == CH_STATE_UP && |
7169 | (card->state == CARD_STATE_UP)) { | 7265 | (card->state == CARD_STATE_UP)) { |
7170 | rtnl_lock(); | 7266 | if(recovery_mode) { |
7171 | dev_close(card->dev); | 7267 | qeth_stop(card->dev); |
7172 | rtnl_unlock(); | 7268 | } else { |
7269 | rtnl_lock(); | ||
7270 | dev_close(card->dev); | ||
7271 | rtnl_unlock(); | ||
7272 | } | ||
7173 | if (!card->use_hard_stop) { | 7273 | if (!card->use_hard_stop) { |
7174 | __u8 *mac = &card->dev->dev_addr[0]; | 7274 | __u8 *mac = &card->dev->dev_addr[0]; |
7175 | rc = qeth_layer2_send_delmac(card, mac); | 7275 | rc = qeth_layer2_send_delmac(card, mac); |
@@ -7341,13 +7441,17 @@ qeth_register_netdev(struct qeth_card *card) | |||
7341 | } | 7441 | } |
7342 | 7442 | ||
7343 | static void | 7443 | static void |
7344 | qeth_start_again(struct qeth_card *card) | 7444 | qeth_start_again(struct qeth_card *card, int recovery_mode) |
7345 | { | 7445 | { |
7346 | QETH_DBF_TEXT(setup ,2, "startag"); | 7446 | QETH_DBF_TEXT(setup ,2, "startag"); |
7347 | 7447 | ||
7348 | rtnl_lock(); | 7448 | if(recovery_mode) { |
7349 | dev_open(card->dev); | 7449 | qeth_open(card->dev); |
7350 | rtnl_unlock(); | 7450 | } else { |
7451 | rtnl_lock(); | ||
7452 | dev_open(card->dev); | ||
7453 | rtnl_unlock(); | ||
7454 | } | ||
7351 | /* this also sets saved unicast addresses */ | 7455 | /* this also sets saved unicast addresses */ |
7352 | qeth_set_multicast_list(card->dev); | 7456 | qeth_set_multicast_list(card->dev); |
7353 | } | 7457 | } |
@@ -7404,7 +7508,7 @@ static void qeth_make_parameters_consistent(struct qeth_card *card) | |||
7404 | 7508 | ||
7405 | 7509 | ||
7406 | static int | 7510 | static int |
7407 | qeth_set_online(struct ccwgroup_device *gdev) | 7511 | __qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode) |
7408 | { | 7512 | { |
7409 | struct qeth_card *card = gdev->dev.driver_data; | 7513 | struct qeth_card *card = gdev->dev.driver_data; |
7410 | int rc = 0; | 7514 | int rc = 0; |
@@ -7464,12 +7568,12 @@ qeth_set_online(struct ccwgroup_device *gdev) | |||
7464 | * we can also use this state for recovery purposes*/ | 7568 | * we can also use this state for recovery purposes*/ |
7465 | qeth_set_allowed_threads(card, 0xffffffff, 0); | 7569 | qeth_set_allowed_threads(card, 0xffffffff, 0); |
7466 | if (recover_flag == CARD_STATE_RECOVER) | 7570 | if (recover_flag == CARD_STATE_RECOVER) |
7467 | qeth_start_again(card); | 7571 | qeth_start_again(card, recovery_mode); |
7468 | qeth_notify_processes(); | 7572 | qeth_notify_processes(); |
7469 | return 0; | 7573 | return 0; |
7470 | out_remove: | 7574 | out_remove: |
7471 | card->use_hard_stop = 1; | 7575 | card->use_hard_stop = 1; |
7472 | qeth_stop_card(card); | 7576 | qeth_stop_card(card, 0); |
7473 | ccw_device_set_offline(CARD_DDEV(card)); | 7577 | ccw_device_set_offline(CARD_DDEV(card)); |
7474 | ccw_device_set_offline(CARD_WDEV(card)); | 7578 | ccw_device_set_offline(CARD_WDEV(card)); |
7475 | ccw_device_set_offline(CARD_RDEV(card)); | 7579 | ccw_device_set_offline(CARD_RDEV(card)); |
@@ -7480,6 +7584,12 @@ out_remove: | |||
7480 | return -ENODEV; | 7584 | return -ENODEV; |
7481 | } | 7585 | } |
7482 | 7586 | ||
7587 | static int | ||
7588 | qeth_set_online(struct ccwgroup_device *gdev) | ||
7589 | { | ||
7590 | return __qeth_set_online(gdev, 0); | ||
7591 | } | ||
7592 | |||
7483 | static struct ccw_device_id qeth_ids[] = { | 7593 | static struct ccw_device_id qeth_ids[] = { |
7484 | {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE}, | 7594 | {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE}, |
7485 | {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD}, | 7595 | {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD}, |