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}, |
