static int qeth_qdio_establish(struct qeth_card *);
 
 
-static inline void __qeth_fill_buffer_frag(struct sk_buff *skb,
-               struct qdio_buffer *buffer, int is_tso,
-               int *next_element_to_fill)
-{
-       struct skb_frag_struct *frag;
-       int fragno;
-       unsigned long addr;
-       int element, cnt, dlen;
-
-       fragno = skb_shinfo(skb)->nr_frags;
-       element = *next_element_to_fill;
-       dlen = 0;
-
-       if (is_tso)
-               buffer->element[element].flags =
-                       SBAL_FLAGS_MIDDLE_FRAG;
-       else
-               buffer->element[element].flags =
-                       SBAL_FLAGS_FIRST_FRAG;
-       dlen = skb->len - skb->data_len;
-       if (dlen) {
-               buffer->element[element].addr = skb->data;
-               buffer->element[element].length = dlen;
-               element++;
-       }
-       for (cnt = 0; cnt < fragno; cnt++) {
-               frag = &skb_shinfo(skb)->frags[cnt];
-               addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
-                       frag->page_offset;
-               buffer->element[element].addr = (char *)addr;
-               buffer->element[element].length = frag->size;
-               if (cnt < (fragno - 1))
-                       buffer->element[element].flags =
-                               SBAL_FLAGS_MIDDLE_FRAG;
-               else
-                       buffer->element[element].flags =
-                               SBAL_FLAGS_LAST_FRAG;
-               element++;
-       }
-       *next_element_to_fill = element;
-}
-
 static inline const char *qeth_get_cardname(struct qeth_card *card)
 {
        if (card->info.guestlan) {
 int qeth_get_elements_no(struct qeth_card *card, void *hdr,
                     struct sk_buff *skb, int elems)
 {
-       int elements_needed = 0;
+       int dlen = skb->len - skb->data_len;
+       int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) -
+               PFN_DOWN((unsigned long)skb->data);
 
-       if (skb_shinfo(skb)->nr_frags > 0)
-               elements_needed = (skb_shinfo(skb)->nr_frags + 1);
-       if (elements_needed == 0)
-               elements_needed = 1 + (((((unsigned long) skb->data) %
-                               PAGE_SIZE) + skb->len) >> PAGE_SHIFT);
+       elements_needed += skb_shinfo(skb)->nr_frags;
        if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
                QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
                        "(Number=%d / Length=%d). Discarded.\n",
 }
 EXPORT_SYMBOL_GPL(qeth_get_elements_no);
 
+int qeth_hdr_chk_and_bounce(struct sk_buff *skb, int len)
+{
+       int hroom, inpage, rest;
+
+       if (((unsigned long)skb->data & PAGE_MASK) !=
+           (((unsigned long)skb->data + len - 1) & PAGE_MASK)) {
+               hroom = skb_headroom(skb);
+               inpage = PAGE_SIZE - ((unsigned long) skb->data % PAGE_SIZE);
+               rest = len - inpage;
+               if (rest > hroom)
+                       return 1;
+               memmove(skb->data - rest, skb->data, skb->len - skb->data_len);
+               skb->data -= rest;
+               QETH_DBF_MESSAGE(2, "skb bounce len: %d rest: %d\n", len, rest);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce);
+
 static inline void __qeth_fill_buffer(struct sk_buff *skb,
        struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill,
        int offset)
 {
-       int length = skb->len;
+       int length = skb->len - skb->data_len;
        int length_here;
        int element;
        char *data;
-       int first_lap ;
+       int first_lap, cnt;
+       struct skb_frag_struct *frag;
 
        element = *next_element_to_fill;
        data = skb->data;
                length -= length_here;
                if (!length) {
                        if (first_lap)
-                               buffer->element[element].flags = 0;
+                               if (skb_shinfo(skb)->nr_frags)
+                                       buffer->element[element].flags =
+                                               SBAL_FLAGS_FIRST_FRAG;
+                               else
+                                       buffer->element[element].flags = 0;
                        else
                                buffer->element[element].flags =
-                                   SBAL_FLAGS_LAST_FRAG;
+                                   SBAL_FLAGS_MIDDLE_FRAG;
                } else {
                        if (first_lap)
                                buffer->element[element].flags =
                element++;
                first_lap = 0;
        }
+
+       for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) {
+               frag = &skb_shinfo(skb)->frags[cnt];
+               buffer->element[element].addr = (char *)page_to_phys(frag->page)
+                       + frag->page_offset;
+               buffer->element[element].length = frag->size;
+               buffer->element[element].flags = SBAL_FLAGS_MIDDLE_FRAG;
+               element++;
+       }
+
+       if (buffer->element[element - 1].flags)
+               buffer->element[element - 1].flags = SBAL_FLAGS_LAST_FRAG;
        *next_element_to_fill = element;
 }
 
                buf->next_element_to_fill++;
        }
 
-       if (skb_shinfo(skb)->nr_frags == 0)
-               __qeth_fill_buffer(skb, buffer, large_send,
-                               (int *)&buf->next_element_to_fill, offset);
-       else
-               __qeth_fill_buffer_frag(skb, buffer, large_send,
-                                       (int *)&buf->next_element_to_fill);
+       __qeth_fill_buffer(skb, buffer, large_send,
+               (int *)&buf->next_element_to_fill, offset);
 
        if (!queue->do_pack) {
                QETH_CARD_TEXT(queue->card, 6, "fillbfnp");
 
        unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
                tcp_hdr(skb)->doff * 4;
        int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data);
-       int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd);
+       int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd);
        elements += skb_shinfo(skb)->nr_frags;
        return elements;
 }
 
-static inline int qeth_l3_tso_check(struct sk_buff *skb)
-{
-       int len = ((unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4) -
-               (unsigned long)skb->data;
-       return (((unsigned long)skb->data & PAGE_MASK) !=
-               (((unsigned long)skb->data + len) & PAGE_MASK));
-}
-
 static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        int rc;
            (cast_type == RTN_UNSPEC)) {
                hdr = (struct qeth_hdr *)skb_push(new_skb,
                                                sizeof(struct qeth_hdr_tso));
-               if (qeth_l3_tso_check(new_skb))
-                       QETH_DBF_MESSAGE(2, "tso skb misaligned\n");
                memset(hdr, 0, sizeof(struct qeth_hdr_tso));
                qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type);
                qeth_tso_fill_header(card, hdr, new_skb);
        elements_needed += elems;
        nr_frags = skb_shinfo(new_skb)->nr_frags;
 
-       if (card->info.type != QETH_CARD_TYPE_IQD)
+       if (card->info.type != QETH_CARD_TYPE_IQD) {
+               int len;
+               if (large_send == QETH_LARGE_SEND_TSO)
+                       len = ((unsigned long)tcp_hdr(new_skb) +
+                               tcp_hdr(new_skb)->doff * 4) -
+                               (unsigned long)new_skb->data;
+               else
+                       len = sizeof(struct qeth_hdr_layer3);
+
+               if (qeth_hdr_chk_and_bounce(new_skb, len))
+                       goto tx_drop;
                rc = qeth_do_send_packet(card, queue, new_skb, hdr,
                                         elements_needed);
-       else
+       } else
                rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
                                        elements_needed, data_offset, 0);