Automatic merge of /spare/repo/netdev-2.6 branch qeth
author <jgarzik@pretzel.yyz.us> <>
Thu, 26 May 2005 02:11:06 +0000 (22:11 -0400)
committerJeff Garzik <jgarzik@pobox.com>
Thu, 26 May 2005 02:11:06 +0000 (22:11 -0400)
14 files changed:
drivers/s390/net/Makefile
drivers/s390/net/ctcdbug.h
drivers/s390/net/ctcmain.c
drivers/s390/net/ctcmain.h [new file with mode: 0644]
drivers/s390/net/ctctty.c
drivers/s390/net/cu3088.c
drivers/s390/net/cu3088.h
drivers/s390/net/iucv.c
drivers/s390/net/lcs.c
drivers/s390/net/qeth.h
drivers/s390/net/qeth_eddp.c
drivers/s390/net/qeth_main.c
drivers/s390/net/qeth_tso.c [deleted file]
drivers/s390/net/qeth_tso.h

index 7cabb80a2e4144ef77210e5576124009baa747f3..90d4d0ef3dd4d54f5b6563e24c68118c654aa74f 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
 obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
 obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
 obj-$(CONFIG_LCS) += lcs.o cu3088.o
-qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o qeth_tso.o
+obj-$(CONFIG_CLAW) += claw.o cu3088.o
+qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o 
 qeth-$(CONFIG_PROC_FS) += qeth_proc.o
 obj-$(CONFIG_QETH) += qeth.o
index ef8883951720c27ea3aa3b1c0abacda934105c0c..7fe2ebd1792dc6de5cbe1ee4a30af420fd76d8fb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.4 $)
+ * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.5 $)
  *
  * CTC / ESCON network driver - s390 dbf exploit.
  *
@@ -9,7 +9,7 @@
  *    Author(s): Original Code written by
  *                       Peter Tiedemann (ptiedem@de.ibm.com)
  *
- *    $Revision: 1.4 $  $Date: 2004/10/15 09:26:58 $
+ *    $Revision: 1.5 $  $Date: 2005/02/27 19:46:44 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-
+#ifndef _CTCDBUG_H_
+#define _CTCDBUG_H_
 
 #include <asm/debug.h>
+#include "ctcmain.h"
 /**
  * Debug Facility stuff
  */
@@ -41,7 +43,7 @@
 #define CTC_DBF_DATA_LEN 128
 #define CTC_DBF_DATA_INDEX 3
 #define CTC_DBF_DATA_NR_AREAS 1
-#define CTC_DBF_DATA_LEVEL 2
+#define CTC_DBF_DATA_LEVEL 3
 
 #define CTC_DBF_TRACE_NAME "ctc_trace"
 #define CTC_DBF_TRACE_LEN 16
@@ -121,3 +123,5 @@ hex_dump(unsigned char *buf, size_t len)
        printk("\n");
 }
 
+
+#endif
index 7266bf5ea6599f9734866b01383032636e4de96f..ff3e95e07e895dc73768f91fe01f93a1b87964c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.72 2005/03/17 10:51:52 ptiedem Exp $
+ * $Id: ctcmain.c,v 1.74 2005/03/24 09:04:17 mschwide Exp $
  *
  * CTC / ESCON network driver
  *
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.72 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.74 $
  *
  */
 \f
 #undef DEBUG
-
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include "ctctty.h"
 #include "fsm.h"
 #include "cu3088.h"
+
 #include "ctcdbug.h"
+#include "ctcmain.h"
 
 MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
 MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
 MODULE_LICENSE("GPL");
-
-/**
- * CCW commands, used in this driver.
- */
-#define CCW_CMD_WRITE          0x01
-#define CCW_CMD_READ           0x02
-#define CCW_CMD_SET_EXTENDED   0xc3
-#define CCW_CMD_PREPARE                0xe3
-
-#define CTC_PROTO_S390          0
-#define CTC_PROTO_LINUX         1
-#define CTC_PROTO_LINUX_TTY     2
-#define CTC_PROTO_OS390         3
-#define CTC_PROTO_MAX           3
-
-#define CTC_BUFSIZE_LIMIT       65535
-#define CTC_BUFSIZE_DEFAULT     32768
-
-#define CTC_TIMEOUT_5SEC        5000
-
-#define CTC_INITIAL_BLOCKLEN    2
-
-#define READ                   0
-#define WRITE                  1
-
-#define CTC_ID_SIZE             BUS_ID_SIZE+3
-\f
-
-struct ctc_profile {
-       unsigned long maxmulti;
-       unsigned long maxcqueue;
-       unsigned long doios_single;
-       unsigned long doios_multi;
-       unsigned long txlen;
-       unsigned long tx_time;
-       struct timespec send_stamp;
-};
-
-/**
- * Definition of one channel
- */
-struct channel {
-
-       /**
-        * Pointer to next channel in list.
-        */
-       struct channel *next;
-       char id[CTC_ID_SIZE];
-       struct ccw_device *cdev;
-
-       /**
-        * Type of this channel.
-        * CTC/A or Escon for valid channels.
-        */
-       enum channel_types type;
-
-       /**
-        * Misc. flags. See CHANNEL_FLAGS_... below
-        */
-       __u32 flags;
-
-       /**
-        * The protocol of this channel
-        */
-       __u16 protocol;
-
-       /**
-        * I/O and irq related stuff
-        */
-       struct ccw1 *ccw;
-       struct irb *irb;
-
-       /**
-        * RX/TX buffer size
-        */
-       int max_bufsize;
-
-       /**
-        * Transmit/Receive buffer.
-        */
-       struct sk_buff *trans_skb;
-
-       /**
-        * Universal I/O queue.
-        */
-       struct sk_buff_head io_queue;
-
-       /**
-        * TX queue for collecting skb's during busy.
-        */
-       struct sk_buff_head collect_queue;
-
-       /**
-        * Amount of data in collect_queue.
-        */
-       int collect_len;
-
-       /**
-        * spinlock for collect_queue and collect_len
-        */
-       spinlock_t collect_lock;
-
-       /**
-        * Timer for detecting unresposive
-        * I/O operations.
-        */
-       fsm_timer timer;
-
-       /**
-        * Retry counter for misc. operations.
-        */
-       int retry;
-
-       /**
-        * The finite state machine of this channel
-        */
-       fsm_instance *fsm;
-
-       /**
-        * The corresponding net_device this channel
-        * belongs to.
-        */
-       struct net_device *netdev;
-
-       struct ctc_profile prof;
-
-       unsigned char *trans_skb_data;
-
-       __u16 logflags;
-};
-
-#define CHANNEL_FLAGS_READ            0
-#define CHANNEL_FLAGS_WRITE           1
-#define CHANNEL_FLAGS_INUSE           2
-#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
-#define CHANNEL_FLAGS_FAILED          8
-#define CHANNEL_FLAGS_WAITIRQ        16
-#define CHANNEL_FLAGS_RWMASK 1
-#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
-
-#define LOG_FLAG_ILLEGALPKT  1
-#define LOG_FLAG_ILLEGALSIZE 2
-#define LOG_FLAG_OVERRUN     4
-#define LOG_FLAG_NOMEM       8
-
-#define CTC_LOGLEVEL_INFO     1
-#define CTC_LOGLEVEL_NOTICE   2
-#define CTC_LOGLEVEL_WARN     4
-#define CTC_LOGLEVEL_EMERG    8
-#define CTC_LOGLEVEL_ERR     16
-#define CTC_LOGLEVEL_DEBUG   32
-#define CTC_LOGLEVEL_CRIT    64
-
-#define CTC_LOGLEVEL_DEFAULT \
-(CTC_LOGLEVEL_INFO | CTC_LOGLEVEL_NOTICE | CTC_LOGLEVEL_WARN | CTC_LOGLEVEL_CRIT)
-
-#define CTC_LOGLEVEL_MAX     ((CTC_LOGLEVEL_CRIT<<1)-1)
-
-static int loglevel = CTC_LOGLEVEL_DEFAULT;
-
-#define ctc_pr_debug(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG fmt,##arg); } while (0)
-
-#define ctc_pr_info(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_INFO) printk(KERN_INFO fmt,##arg); } while (0)
-
-#define ctc_pr_notice(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_NOTICE) printk(KERN_NOTICE fmt,##arg); } while (0)
-
-#define ctc_pr_warn(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING fmt,##arg); } while (0)
-
-#define ctc_pr_emerg(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_EMERG) printk(KERN_EMERG fmt,##arg); } while (0)
-
-#define ctc_pr_err(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_ERR) printk(KERN_ERR fmt,##arg); } while (0)
-
-#define ctc_pr_crit(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_CRIT) printk(KERN_CRIT fmt,##arg); } while (0)
-
-/**
- * Linked list of all detected channels.
- */
-static struct channel *channels = NULL;
-
-struct ctc_priv {
-       struct net_device_stats stats;
-       unsigned long tbusy;
-       /**
-        * The finite state machine of this interface.
-        */
-       fsm_instance *fsm;
-       /**
-        * The protocol of this device
-        */
-       __u16 protocol;
-       /**
-        * Timer for restarting after I/O Errors
-        */
-       fsm_timer               restart_timer;
-
-       int buffer_size;
-
-       struct channel *channel[2];
-};
-
-/**
- * Definition of our link level header.
- */
-struct ll_header {
-       __u16 length;
-       __u16 type;
-       __u16 unused;
-};
-#define LL_HEADER_LENGTH (sizeof(struct ll_header))
-
-/**
- * Compatibility macros for busy handling
- * of network devices.
- */
-static __inline__ void
-ctc_clear_busy(struct net_device * dev)
-{
-       clear_bit(0, &(((struct ctc_priv *) dev->priv)->tbusy));
-       if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
-               netif_wake_queue(dev);
-}
-
-static __inline__ int
-ctc_test_and_set_busy(struct net_device * dev)
-{
-       if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
-               netif_stop_queue(dev);
-       return test_and_set_bit(0, &((struct ctc_priv *) dev->priv)->tbusy);
-}
-
-/**
- * Print Banner.
- */
-static void
-print_banner(void)
-{
-       static int printed = 0;
-       char vbuf[] = "$Revision: 1.72 $";
-       char *version = vbuf;
-
-       if (printed)
-               return;
-       if ((version = strchr(version, ':'))) {
-               char *p = strchr(version + 1, '$');
-               if (p)
-                       *p = '\0';
-       } else
-               version = " ??? ";
-       printk(KERN_INFO "CTC driver Version%s"
-#ifdef DEBUG
-                   " (DEBUG-VERSION, " __DATE__ __TIME__ ")"
-#endif
-                   " initialized\n", version);
-       printed = 1;
-}
-\f
-/**
- * Return type of a detected device.
- */
-static enum channel_types
-get_channel_type(struct ccw_device_id *id)
-{
-       enum channel_types type = (enum channel_types) id->driver_info;
-
-       if (type == channel_type_ficon)
-               type = channel_type_escon;
-
-       return type;
-}
-\f
 /**
  * States of the interface statemachine.
  */
@@ -371,7 +95,7 @@ enum dev_states {
        /**
         * MUST be always the last element!!
         */
-       NR_DEV_STATES
+       CTC_NR_DEV_STATES
 };
 
 static const char *dev_state_names[] = {
@@ -399,7 +123,7 @@ enum dev_events {
        /**
         * MUST be always the last element!!
         */
-       NR_DEV_EVENTS
+       CTC_NR_DEV_EVENTS
 };
 
 static const char *dev_event_names[] = {
@@ -476,40 +200,6 @@ enum ch_events {
        NR_CH_EVENTS,
 };
 
-static const char *ch_event_names[] = {
-       "ccw_device success",
-       "ccw_device busy",
-       "ccw_device enodev",
-       "ccw_device ioerr",
-       "ccw_device unknown",
-
-       "Status ATTN & BUSY",
-       "Status ATTN",
-       "Status BUSY",
-
-       "Unit check remote reset",
-       "Unit check remote system reset",
-       "Unit check TX timeout",
-       "Unit check TX parity",
-       "Unit check Hardware failure",
-       "Unit check RX parity",
-       "Unit check ZERO",
-       "Unit check Unknown",
-
-       "SubChannel check Unknown",
-
-       "Machine check failure",
-       "Machine check operational",
-
-       "IRQ normal",
-       "IRQ final",
-
-       "Timer",
-
-       "Start",
-       "Stop",
-};
-
 /**
  * States of the channel statemachine.
  */
@@ -545,6 +235,87 @@ enum ch_states {
        NR_CH_STATES,
 };
 
+static int loglevel = CTC_LOGLEVEL_DEFAULT;
+
+/**
+ * Linked list of all detected channels.
+ */
+static struct channel *channels = NULL;
+
+/**
+ * Print Banner.
+ */
+static void
+print_banner(void)
+{
+       static int printed = 0;
+       char vbuf[] = "$Revision: 1.74 $";
+       char *version = vbuf;
+
+       if (printed)
+               return;
+       if ((version = strchr(version, ':'))) {
+               char *p = strchr(version + 1, '$');
+               if (p)
+                       *p = '\0';
+       } else
+               version = " ??? ";
+       printk(KERN_INFO "CTC driver Version%s"
+#ifdef DEBUG
+                   " (DEBUG-VERSION, " __DATE__ __TIME__ ")"
+#endif
+                   " initialized\n", version);
+       printed = 1;
+}
+
+/**
+ * Return type of a detected device.
+ */
+static enum channel_types
+get_channel_type(struct ccw_device_id *id)
+{
+       enum channel_types type = (enum channel_types) id->driver_info;
+
+       if (type == channel_type_ficon)
+               type = channel_type_escon;
+
+       return type;
+}
+
+static const char *ch_event_names[] = {
+       "ccw_device success",
+       "ccw_device busy",
+       "ccw_device enodev",
+       "ccw_device ioerr",
+       "ccw_device unknown",
+
+       "Status ATTN & BUSY",
+       "Status ATTN",
+       "Status BUSY",
+
+       "Unit check remote reset",
+       "Unit check remote system reset",
+       "Unit check TX timeout",
+       "Unit check TX parity",
+       "Unit check Hardware failure",
+       "Unit check RX parity",
+       "Unit check ZERO",
+       "Unit check Unknown",
+
+       "SubChannel check Unknown",
+
+       "Machine check failure",
+       "Machine check operational",
+
+       "IRQ normal",
+       "IRQ final",
+
+       "Timer",
+
+       "Start",
+       "Stop",
+};
+
 static const char *ch_state_names[] = {
        "Idle",
        "Stopped",
@@ -1934,7 +1705,6 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
        ch->cdev = cdev;
        snprintf(ch->id, CTC_ID_SIZE, "ch-%s", cdev->dev.bus_id);
        ch->type = type;
-       loglevel = CTC_LOGLEVEL_DEFAULT;
        ch->fsm = init_fsm(ch->id, ch_state_names,
                           ch_event_names, NR_CH_STATES, NR_CH_EVENTS,
                           ch_fsm, CH_FSM_LEN, GFP_KERNEL);
@@ -2697,6 +2467,7 @@ ctc_stats(struct net_device * dev)
 /*
  * sysfs attributes
  */
+
 static ssize_t
 buffer_show(struct device *dev, char *buf)
 {
@@ -2715,57 +2486,61 @@ buffer_write(struct device *dev, const char *buf, size_t count)
        struct ctc_priv *priv;
        struct net_device *ndev;
        int bs1;
+       char buffer[16];
 
        DBF_TEXT(trace, 3, __FUNCTION__);
+       DBF_TEXT(trace, 3, buf);
        priv = dev->driver_data;
-       if (!priv)
+       if (!priv) {
+               DBF_TEXT(trace, 3, "bfnopriv");
                return -ENODEV;
+       }
+
+       sscanf(buf, "%u", &bs1);
+       if (bs1 > CTC_BUFSIZE_LIMIT)
+               goto einval;
+       if (bs1 < (576 + LL_HEADER_LENGTH + 2))
+               goto einval;
+       priv->buffer_size = bs1;        // just to overwrite the default
+
        ndev = priv->channel[READ]->netdev;
-       if (!ndev)
+       if (!ndev) {
+               DBF_TEXT(trace, 3, "bfnondev");
                return -ENODEV;
-       sscanf(buf, "%u", &bs1);
+       }
 
-       if (bs1 > CTC_BUFSIZE_LIMIT)
-               return -EINVAL;
        if ((ndev->flags & IFF_RUNNING) &&
            (bs1 < (ndev->mtu + LL_HEADER_LENGTH + 2)))
-               return -EINVAL;
-       if (bs1 < (576 + LL_HEADER_LENGTH + 2))
-               return -EINVAL;
+               goto einval;
 
-       priv->buffer_size = bs1;
-       priv->channel[READ]->max_bufsize =
-           priv->channel[WRITE]->max_bufsize = bs1;
+       priv->channel[READ]->max_bufsize = bs1;
+       priv->channel[WRITE]->max_bufsize = bs1;
        if (!(ndev->flags & IFF_RUNNING))
                ndev->mtu = bs1 - LL_HEADER_LENGTH - 2;
        priv->channel[READ]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
        priv->channel[WRITE]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
 
+       sprintf(buffer, "%d",priv->buffer_size);
+       DBF_TEXT(trace, 3, buffer);
        return count;
 
+einval:
+       DBF_TEXT(trace, 3, "buff_err");
+       return -EINVAL;
 }
 
 static ssize_t
 loglevel_show(struct device *dev, char *buf)
 {
-       struct ctc_priv *priv;
-
-       priv = dev->driver_data;
-       if (!priv)
-               return -ENODEV;
        return sprintf(buf, "%d\n", loglevel);
 }
 
 static ssize_t
 loglevel_write(struct device *dev, const char *buf, size_t count)
 {
-       struct ctc_priv *priv;
        int ll1;
 
        DBF_TEXT(trace, 5, __FUNCTION__);
-       priv = dev->driver_data;
-       if (!priv)
-               return -ENODEV;
        sscanf(buf, "%i", &ll1);
 
        if ((ll1 > CTC_LOGLEVEL_MAX) || (ll1 < 0))
@@ -2835,27 +2610,6 @@ stats_write(struct device *dev, const char *buf, size_t count)
        return count;
 }
 
-static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
-static DEVICE_ATTR(loglevel, 0644, loglevel_show, loglevel_write);
-static DEVICE_ATTR(stats, 0644, stats_show, stats_write);
-
-static int
-ctc_add_attributes(struct device *dev)
-{
-//     device_create_file(dev, &dev_attr_buffer);
-       device_create_file(dev, &dev_attr_loglevel);
-       device_create_file(dev, &dev_attr_stats);
-       return 0;
-}
-
-static void
-ctc_remove_attributes(struct device *dev)
-{
-       device_remove_file(dev, &dev_attr_stats);
-       device_remove_file(dev, &dev_attr_loglevel);
-//     device_remove_file(dev, &dev_attr_buffer);
-}
-
 \f
 static void
 ctc_netdev_unregister(struct net_device * dev)
@@ -2899,52 +2653,6 @@ ctc_free_netdevice(struct net_device * dev, int free_dev)
 #endif
 }
 
-/**
- * Initialize everything of the net device except the name and the
- * channel structs.
- */
-static struct net_device *
-ctc_init_netdevice(struct net_device * dev, int alloc_device, 
-                  struct ctc_priv *privptr)
-{
-       if (!privptr)
-               return NULL;
-
-       DBF_TEXT(setup, 3, __FUNCTION__);
-       if (alloc_device) {
-               dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
-               if (!dev)
-                       return NULL;
-               memset(dev, 0, sizeof (struct net_device));
-       }
-
-       dev->priv = privptr;
-       privptr->fsm = init_fsm("ctcdev", dev_state_names,
-                               dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
-                               dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
-       if (privptr->fsm == NULL) {
-               if (alloc_device)
-                       kfree(dev);
-               return NULL;
-       }
-       fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
-       fsm_settimer(privptr->fsm, &privptr->restart_timer);
-       if (dev->mtu == 0)
-               dev->mtu = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
-       dev->hard_start_xmit = ctc_tx;
-       dev->open = ctc_open;
-       dev->stop = ctc_close;
-       dev->get_stats = ctc_stats;
-       dev->change_mtu = ctc_change_mtu;
-       dev->hard_header_len = LL_HEADER_LENGTH + 2;
-       dev->addr_len = 0;
-       dev->type = ARPHRD_SLIP;
-       dev->tx_queue_len = 100;
-       dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-       SET_MODULE_OWNER(dev);
-       return dev;
-}
-
 static ssize_t
 ctc_proto_show(struct device *dev, char *buf)
 {
@@ -2977,7 +2685,6 @@ ctc_proto_store(struct device *dev, const char *buf, size_t count)
        return count;
 }
 
-static DEVICE_ATTR(protocol, 0644, ctc_proto_show, ctc_proto_store);
 
 static ssize_t
 ctc_type_show(struct device *dev, char *buf)
@@ -2991,8 +2698,13 @@ ctc_type_show(struct device *dev, char *buf)
        return sprintf(buf, "%s\n", cu3088_type[cgdev->cdev[0]->id.driver_info]);
 }
 
+static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
+static DEVICE_ATTR(protocol, 0644, ctc_proto_show, ctc_proto_store);
 static DEVICE_ATTR(type, 0444, ctc_type_show, NULL);
 
+static DEVICE_ATTR(loglevel, 0644, loglevel_show, loglevel_write);
+static DEVICE_ATTR(stats, 0644, stats_show, stats_write);
+
 static struct attribute *ctc_attr[] = {
        &dev_attr_protocol.attr,
        &dev_attr_type.attr,
@@ -3004,6 +2716,21 @@ static struct attribute_group ctc_attr_group = {
        .attrs = ctc_attr,
 };
 
+static int
+ctc_add_attributes(struct device *dev)
+{
+       device_create_file(dev, &dev_attr_loglevel);
+       device_create_file(dev, &dev_attr_stats);
+       return 0;
+}
+
+static void
+ctc_remove_attributes(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_stats);
+       device_remove_file(dev, &dev_attr_loglevel);
+}
+
 static int
 ctc_add_files(struct device *dev)
 {
@@ -3028,15 +2755,15 @@ ctc_remove_files(struct device *dev)
  *
  * @returns 0 on success, !0 on failure.
  */
-
 static int
 ctc_probe_device(struct ccwgroup_device *cgdev)
 {
        struct ctc_priv *priv;
        int rc;
+       char buffer[16];
 
        pr_debug("%s() called\n", __FUNCTION__);
-       DBF_TEXT(trace, 3, __FUNCTION__);
+       DBF_TEXT(setup, 3, __FUNCTION__);
 
        if (!get_device(&cgdev->dev))
                return -ENODEV;
@@ -3060,9 +2787,69 @@ ctc_probe_device(struct ccwgroup_device *cgdev)
        cgdev->cdev[1]->handler = ctc_irq_handler;
        cgdev->dev.driver_data = priv;
 
+       sprintf(buffer, "%p", priv);
+       DBF_TEXT(data, 3, buffer);
+
+       sprintf(buffer, "%u", (unsigned int)sizeof(struct ctc_priv));
+       DBF_TEXT(data, 3, buffer);
+
+       sprintf(buffer, "%p", &channels);
+       DBF_TEXT(data, 3, buffer);
+
+       sprintf(buffer, "%u", (unsigned int)sizeof(struct channel));
+       DBF_TEXT(data, 3, buffer);
+
        return 0;
 }
 
+/**
+ * Initialize everything of the net device except the name and the
+ * channel structs.
+ */
+static struct net_device *
+ctc_init_netdevice(struct net_device * dev, int alloc_device,
+                  struct ctc_priv *privptr)
+{
+       if (!privptr)
+               return NULL;
+
+       DBF_TEXT(setup, 3, __FUNCTION__);
+
+       if (alloc_device) {
+               dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
+               if (!dev)
+                       return NULL;
+               memset(dev, 0, sizeof (struct net_device));
+       }
+
+       dev->priv = privptr;
+       privptr->fsm = init_fsm("ctcdev", dev_state_names,
+                               dev_event_names, CTC_NR_DEV_STATES, CTC_NR_DEV_EVENTS,
+                               dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
+       if (privptr->fsm == NULL) {
+               if (alloc_device)
+                       kfree(dev);
+               return NULL;
+       }
+       fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
+       fsm_settimer(privptr->fsm, &privptr->restart_timer);
+       if (dev->mtu == 0)
+               dev->mtu = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
+       dev->hard_start_xmit = ctc_tx;
+       dev->open = ctc_open;
+       dev->stop = ctc_close;
+       dev->get_stats = ctc_stats;
+       dev->change_mtu = ctc_change_mtu;
+       dev->hard_header_len = LL_HEADER_LENGTH + 2;
+       dev->addr_len = 0;
+       dev->type = ARPHRD_SLIP;
+       dev->tx_queue_len = 100;
+       dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+       SET_MODULE_OWNER(dev);
+       return dev;
+}
+
+
 /**
  *
  * Setup an interface.
@@ -3081,6 +2868,7 @@ ctc_new_device(struct ccwgroup_device *cgdev)
        struct ctc_priv *privptr;
        struct net_device *dev;
        int ret;
+       char buffer[16];
 
        pr_debug("%s() called\n", __FUNCTION__);
        DBF_TEXT(setup, 3, __FUNCTION__);
@@ -3089,6 +2877,9 @@ ctc_new_device(struct ccwgroup_device *cgdev)
        if (!privptr)
                return -ENODEV;
 
+       sprintf(buffer, "%d", privptr->buffer_size);
+       DBF_TEXT(setup, 3, buffer);
+
        type = get_channel_type(&cgdev->cdev[0]->id);
        
        snprintf(read_id, CTC_ID_SIZE, "ch-%s", cgdev->cdev[0]->dev.bus_id);
@@ -3177,9 +2968,10 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
        struct ctc_priv *priv;
        struct net_device *ndev;
                
-       DBF_TEXT(trace, 3, __FUNCTION__);
+       DBF_TEXT(setup, 3, __FUNCTION__);
        pr_debug("%s() called\n", __FUNCTION__);
 
+
        priv = cgdev->dev.driver_data;
        ndev = NULL;
        if (!priv)
@@ -3215,7 +3007,6 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
                channel_remove(priv->channel[READ]);
        if (priv->channel[WRITE])
                channel_remove(priv->channel[WRITE]);
-       
        priv->channel[READ] = priv->channel[WRITE] = NULL;
 
        return 0;
@@ -3228,7 +3019,7 @@ ctc_remove_device(struct ccwgroup_device *cgdev)
        struct ctc_priv *priv;
 
        pr_debug("%s() called\n", __FUNCTION__);
-       DBF_TEXT(trace, 3, __FUNCTION__);
+       DBF_TEXT(setup, 3, __FUNCTION__);
 
        priv = cgdev->dev.driver_data;
        if (!priv)
@@ -3265,6 +3056,7 @@ static struct ccwgroup_driver ctc_group_driver = {
 static void __exit
 ctc_exit(void)
 {
+       DBF_TEXT(setup, 3, __FUNCTION__);
        unregister_cu3088_discipline(&ctc_group_driver);
        ctc_tty_cleanup();
        ctc_unregister_dbf_views();
@@ -3282,6 +3074,10 @@ ctc_init(void)
 {
        int ret = 0;
 
+       loglevel = CTC_LOGLEVEL_DEFAULT;
+
+       DBF_TEXT(setup, 3, __FUNCTION__);
+
        print_banner();
 
        ret = ctc_register_dbf_views();
diff --git a/drivers/s390/net/ctcmain.h b/drivers/s390/net/ctcmain.h
new file mode 100644 (file)
index 0000000..ba3605f
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * $Id: ctcmain.h,v 1.4 2005/03/24 09:04:17 mschwide Exp $
+ *
+ * CTC / ESCON network driver
+ *
+ * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+             Peter Tiedemann (ptiedem@de.ibm.com)
+ *
+ *
+ * Documentation used:
+ *  - Principles of Operation (IBM doc#: SA22-7201-06)
+ *  - Common IO/-Device Commands and Self Description (IBM doc#: SA22-7204-02)
+ *  - Common IO/-Device Commands and Self Description (IBM doc#: SN22-5535)
+ *  - ESCON Channel-to-Channel Adapter (IBM doc#: SA22-7203-00)
+ *  - ESCON I/O Interface (IBM doc#: SA22-7202-029
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.4 $
+ *
+ */
+
+#ifndef _CTCMAIN_H_
+#define _CTCMAIN_H_
+
+#include <asm/ccwdev.h>
+#include <asm/ccwgroup.h>
+
+#include "ctctty.h"
+#include "fsm.h"
+#include "cu3088.h"
+
+
+/**
+ * CCW commands, used in this driver.
+ */
+#define CCW_CMD_WRITE          0x01
+#define CCW_CMD_READ           0x02
+#define CCW_CMD_SET_EXTENDED   0xc3
+#define CCW_CMD_PREPARE                0xe3
+
+#define CTC_PROTO_S390          0
+#define CTC_PROTO_LINUX         1
+#define CTC_PROTO_LINUX_TTY     2
+#define CTC_PROTO_OS390         3
+#define CTC_PROTO_MAX           3
+
+#define CTC_BUFSIZE_LIMIT       65535
+#define CTC_BUFSIZE_DEFAULT     32768
+
+#define CTC_TIMEOUT_5SEC        5000
+
+#define CTC_INITIAL_BLOCKLEN    2
+
+#define READ                   0
+#define WRITE                  1
+
+#define CTC_ID_SIZE             BUS_ID_SIZE+3
+
+
+struct ctc_profile {
+       unsigned long maxmulti;
+       unsigned long maxcqueue;
+       unsigned long doios_single;
+       unsigned long doios_multi;
+       unsigned long txlen;
+       unsigned long tx_time;
+       struct timespec send_stamp;
+};
+
+/**
+ * Definition of one channel
+ */
+struct channel {
+
+       /**
+        * Pointer to next channel in list.
+        */
+       struct channel *next;
+       char id[CTC_ID_SIZE];
+       struct ccw_device *cdev;
+
+       /**
+        * Type of this channel.
+        * CTC/A or Escon for valid channels.
+        */
+       enum channel_types type;
+
+       /**
+        * Misc. flags. See CHANNEL_FLAGS_... below
+        */
+       __u32 flags;
+
+       /**
+        * The protocol of this channel
+        */
+       __u16 protocol;
+
+       /**
+        * I/O and irq related stuff
+        */
+       struct ccw1 *ccw;
+       struct irb *irb;
+
+       /**
+        * RX/TX buffer size
+        */
+       int max_bufsize;
+
+       /**
+        * Transmit/Receive buffer.
+        */
+       struct sk_buff *trans_skb;
+
+       /**
+        * Universal I/O queue.
+        */
+       struct sk_buff_head io_queue;
+
+       /**
+        * TX queue for collecting skb's during busy.
+        */
+       struct sk_buff_head collect_queue;
+
+       /**
+        * Amount of data in collect_queue.
+        */
+       int collect_len;
+
+       /**
+        * spinlock for collect_queue and collect_len
+        */
+       spinlock_t collect_lock;
+
+       /**
+        * Timer for detecting unresposive
+        * I/O operations.
+        */
+       fsm_timer timer;
+
+       /**
+        * Retry counter for misc. operations.
+        */
+       int retry;
+
+       /**
+        * The finite state machine of this channel
+        */
+       fsm_instance *fsm;
+
+       /**
+        * The corresponding net_device this channel
+        * belongs to.
+        */
+       struct net_device *netdev;
+
+       struct ctc_profile prof;
+
+       unsigned char *trans_skb_data;
+
+       __u16 logflags;
+};
+
+#define CHANNEL_FLAGS_READ            0
+#define CHANNEL_FLAGS_WRITE           1
+#define CHANNEL_FLAGS_INUSE           2
+#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
+#define CHANNEL_FLAGS_FAILED          8
+#define CHANNEL_FLAGS_WAITIRQ        16
+#define CHANNEL_FLAGS_RWMASK 1
+#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
+
+#define LOG_FLAG_ILLEGALPKT  1
+#define LOG_FLAG_ILLEGALSIZE 2
+#define LOG_FLAG_OVERRUN     4
+#define LOG_FLAG_NOMEM       8
+
+#define CTC_LOGLEVEL_INFO     1
+#define CTC_LOGLEVEL_NOTICE   2
+#define CTC_LOGLEVEL_WARN     4
+#define CTC_LOGLEVEL_EMERG    8
+#define CTC_LOGLEVEL_ERR     16
+#define CTC_LOGLEVEL_DEBUG   32
+#define CTC_LOGLEVEL_CRIT    64
+
+#define CTC_LOGLEVEL_DEFAULT \
+(CTC_LOGLEVEL_INFO | CTC_LOGLEVEL_NOTICE | CTC_LOGLEVEL_WARN | CTC_LOGLEVEL_CRIT)
+
+#define CTC_LOGLEVEL_MAX     ((CTC_LOGLEVEL_CRIT<<1)-1)
+
+#define ctc_pr_debug(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG fmt,##arg); } while (0)
+
+#define ctc_pr_info(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_INFO) printk(KERN_INFO fmt,##arg); } while (0)
+
+#define ctc_pr_notice(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_NOTICE) printk(KERN_NOTICE fmt,##arg); } while (0)
+
+#define ctc_pr_warn(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING fmt,##arg); } while (0)
+
+#define ctc_pr_emerg(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_EMERG) printk(KERN_EMERG fmt,##arg); } while (0)
+
+#define ctc_pr_err(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_ERR) printk(KERN_ERR fmt,##arg); } while (0)
+
+#define ctc_pr_crit(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_CRIT) printk(KERN_CRIT fmt,##arg); } while (0)
+
+struct ctc_priv {
+       struct net_device_stats stats;
+       unsigned long tbusy;
+       /**
+        * The finite state machine of this interface.
+        */
+       fsm_instance *fsm;
+       /**
+        * The protocol of this device
+        */
+       __u16 protocol;
+       /**
+        * Timer for restarting after I/O Errors
+        */
+       fsm_timer               restart_timer;
+
+       int buffer_size;
+
+       struct channel *channel[2];
+};
+
+/**
+ * Definition of our link level header.
+ */
+struct ll_header {
+       __u16 length;
+       __u16 type;
+       __u16 unused;
+};
+#define LL_HEADER_LENGTH (sizeof(struct ll_header))
+
+/**
+ * Compatibility macros for busy handling
+ * of network devices.
+ */
+static __inline__ void
+ctc_clear_busy(struct net_device * dev)
+{
+       clear_bit(0, &(((struct ctc_priv *) dev->priv)->tbusy));
+       if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
+               netif_wake_queue(dev);
+}
+
+static __inline__ int
+ctc_test_and_set_busy(struct net_device * dev)
+{
+       if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
+               netif_stop_queue(dev);
+       return test_and_set_bit(0, &((struct ctc_priv *) dev->priv)->tbusy);
+}
+
+#endif
index 9257d60c78330478bca8a05280fda54054ceb9c4..3080393e823db43117d22a6bd73adf7cfdcc6013 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ctctty.c,v 1.26 2004/08/04 11:06:55 mschwide Exp $
+ * $Id: ctctty.c,v 1.29 2005/04/05 08:50:44 mschwide Exp $
  *
  * CTC / ESCON network driver, tty interface.
  *
@@ -1056,8 +1056,7 @@ ctc_tty_close(struct tty_struct *tty, struct file *filp)
        info->tty = 0;
        tty->closing = 0;
        if (info->blocked_open) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ/2);
+               msleep_interruptible(500);
                wake_up_interruptible(&info->open_wait);
        }
        info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING);
index 1b0a9f16024c5929f0062972d431fd33088bb1d7..0075894c71db0e09086efd97b55111f0a374bbe0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cu3088.c,v 1.34 2004/06/15 13:16:27 pavlic Exp $
+ * $Id: cu3088.c,v 1.35 2005/03/30 19:28:52 richtera Exp $
  *
  * CTC / LCS ccw_device driver
  *
@@ -39,6 +39,7 @@ const char *cu3088_type[] = {
        "FICON channel",
        "P390 LCS card",
        "OSA LCS card",
+       "CLAW channel device",
        "unknown channel type",
        "unsupported channel type",
 };
@@ -51,6 +52,7 @@ static struct ccw_device_id cu3088_ids[] = {
        { CCW_DEVICE(0x3088, 0x1e), .driver_info = channel_type_ficon },
        { CCW_DEVICE(0x3088, 0x01), .driver_info = channel_type_p390 },
        { CCW_DEVICE(0x3088, 0x60), .driver_info = channel_type_osa2 },
+       { CCW_DEVICE(0x3088, 0x61), .driver_info = channel_type_claw },
        { /* end of list */ }
 };
 
index 0ec49a8b3adcc5a2e697d01313120e18ad43fc4a..1753661f702a196325968df22cffec4485743f5e 100644 (file)
@@ -23,6 +23,9 @@ enum channel_types {
        /* Device is a OSA2 card */
        channel_type_osa2,
 
+       /* Device is a CLAW channel device */
+       channel_type_claw,
+
        /* Device is a channel, but we don't know
         * anything about it */
        channel_type_unknown,
index 1ac6563ee3e0fd0574f8e79e275130606defed3d..e08e74e16124704b1f7b8bede6092a2d1cab376e 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: iucv.c,v 1.43 2005/02/09 14:47:43 braunu Exp $
+ * $Id: iucv.c,v 1.45 2005/04/26 22:59:06 braunu Exp $
  *
  * IUCV network driver
  *
@@ -29,7 +29,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.43 $
+ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.45 $
  *
  */
 \f
@@ -355,7 +355,7 @@ do { \
 static void
 iucv_banner(void)
 {
-       char vbuf[] = "$Revision: 1.43 $";
+       char vbuf[] = "$Revision: 1.45 $";
        char *version = vbuf;
 
        if ((version = strchr(version, ':'))) {
@@ -2553,12 +2553,12 @@ EXPORT_SYMBOL (iucv_resume);
 #endif
 EXPORT_SYMBOL (iucv_reply_prmmsg);
 EXPORT_SYMBOL (iucv_send);
-#if 0
 EXPORT_SYMBOL (iucv_send2way);
 EXPORT_SYMBOL (iucv_send2way_array);
-EXPORT_SYMBOL (iucv_send_array);
 EXPORT_SYMBOL (iucv_send2way_prmmsg);
 EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
+#if 0
+EXPORT_SYMBOL (iucv_send_array);
 EXPORT_SYMBOL (iucv_send_prmmsg);
 EXPORT_SYMBOL (iucv_setmask);
 #endif
index 0f76e945b9841dadd2ac93b4c627fca18d0e9c84..cccfed248e701ef939bb022c975558f5097c54ca 100644 (file)
@@ -11,7 +11,7 @@
  *                       Frank Pavlic (pavlic@de.ibm.com) and
  *                       Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
- *    $Revision: 1.96 $         $Date: 2004/11/11 13:42:33 $
+ *    $Revision: 1.98 $         $Date: 2005/04/18 13:41:29 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -59,7 +59,7 @@
 /**
  * initialization string for output
  */
-#define VERSION_LCS_C  "$Revision: 1.96 $"
+#define VERSION_LCS_C  "$Revision: 1.98 $"
 
 static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
 static char debug_buffer[255];
@@ -1098,14 +1098,6 @@ lcs_check_multicast_support(struct lcs_card *card)
                PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n");
                return -EOPNOTSUPP;
        }
-       /* Print out supported assists: IPv6 */
-       PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name,
-                  (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?
-                  "with" : "without");
-       /* Print out supported assist: Multicast */
-       PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name,
-                  (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?
-                  "with" : "without");
        if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT)
                return 0;
        return -EOPNOTSUPP;
@@ -1160,7 +1152,7 @@ list_modified:
                }
        }
        /* re-insert all entries from the failed_list into ipm_list */
-       list_for_each_entry(ipm, &failed_list, list) {
+       list_for_each_entry_safe(ipm, tmp, &failed_list, list) {
                list_del_init(&ipm->list);
                list_add_tail(&ipm->list, &card->ipm_list);
        }
@@ -2198,30 +2190,39 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
        if (!dev)
                goto out;
        card->dev = dev;
-netdev_out:
        card->dev->priv = card;
        card->dev->open = lcs_open_device;
        card->dev->stop = lcs_stop_device;
        card->dev->hard_start_xmit = lcs_start_xmit;
        card->dev->get_stats = lcs_getstats;
        SET_MODULE_OWNER(dev);
-       if (lcs_register_netdev(ccwgdev) != 0)
-               goto out;
        memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
 #ifdef CONFIG_IP_MULTICAST
        if (!lcs_check_multicast_support(card))
                card->dev->set_multicast_list = lcs_set_multicast_list;
 #endif
-       netif_stop_queue(card->dev);
+netdev_out:
        lcs_set_allowed_threads(card,0xffffffff);
        if (recover_state == DEV_STATE_RECOVER) {
                lcs_set_multicast_list(card->dev);
                card->dev->flags |= IFF_UP;
                netif_wake_queue(card->dev);
                card->state = DEV_STATE_UP;
-       } else
+       } else {
                lcs_stopcard(card);
+       }
 
+       if (lcs_register_netdev(ccwgdev) != 0)
+               goto out;
+
+       /* Print out supported assists: IPv6 */
+       PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name,
+                  (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?
+                  "with" : "without");
+       /* Print out supported assist: Multicast */
+       PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name,
+                  (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?
+                  "with" : "without");
        return 0;
 out:
 
index a341041a6cf77358955232fae17fa61ef09b4107..a755b57db46b359c9cb632919fc71ef7fd9c52fd 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "qeth_mpc.h"
 
-#define VERSION_QETH_H                 "$Revision: 1.135 $"
+#define VERSION_QETH_H                 "$Revision: 1.139 $"
 
 #ifdef CONFIG_QETH_IPV6
 #define QETH_VERSION_IPV6      ":IPv6"
@@ -288,7 +288,8 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
 #define QETH_TX_TIMEOUT                100 * HZ
 #define QETH_HEADER_SIZE       32
 #define MAX_PORTNO             15
-#define QETH_FAKE_LL_LEN       ETH_HLEN
+#define QETH_FAKE_LL_LEN_ETH   ETH_HLEN
+#define QETH_FAKE_LL_LEN_TR    (sizeof(struct trh_hdr)-TR_MAXRIFLEN+sizeof(struct trllc))
 #define QETH_FAKE_LL_V6_ADDR_POS 24
 
 /*IPv6 address autoconfiguration stuff*/
@@ -369,6 +370,25 @@ struct qeth_hdr {
        } hdr;
 } __attribute__ ((packed));
 
+/*TCP Segmentation Offload header*/
+struct qeth_hdr_ext_tso {
+        __u16 hdr_tot_len;
+        __u8  imb_hdr_no;
+        __u8  reserved;
+        __u8  hdr_type;
+        __u8  hdr_version;
+        __u16 hdr_len;
+        __u32 payload_len;
+        __u16 mss;
+        __u16 dg_hdr_len;
+        __u8  padding[16];
+} __attribute__ ((packed));
+
+struct qeth_hdr_tso {
+        struct qeth_hdr hdr;   /*hdr->hdr.l3.xxx*/
+       struct qeth_hdr_ext_tso ext;
+} __attribute__ ((packed));
+
 
 /* flags for qeth_hdr.flags */
 #define QETH_HDR_PASSTHRU 0x10
@@ -866,6 +886,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
         return hdr;
 }
 
+
 inline static int
 qeth_get_hlen(__u8 link_type)
 {
@@ -873,19 +894,19 @@ qeth_get_hlen(__u8 link_type)
        switch (link_type) {
        case QETH_LINK_TYPE_HSTR:
        case QETH_LINK_TYPE_LANE_TR:
-               return sizeof(struct qeth_hdr) + TR_HLEN;
+               return sizeof(struct qeth_hdr_tso) + TR_HLEN;
        default:
 #ifdef CONFIG_QETH_VLAN
-               return sizeof(struct qeth_hdr) + VLAN_ETH_HLEN;
+               return sizeof(struct qeth_hdr_tso) + VLAN_ETH_HLEN;
 #else
-               return sizeof(struct qeth_hdr) + ETH_HLEN;
+               return sizeof(struct qeth_hdr_tso) + ETH_HLEN;
 #endif
        }
 #else  /* CONFIG_QETH_IPV6 */
 #ifdef CONFIG_QETH_VLAN
-       return sizeof(struct qeth_hdr) + VLAN_HLEN;
+       return sizeof(struct qeth_hdr_tso) + VLAN_HLEN;
 #else
-       return sizeof(struct qeth_hdr);
+       return sizeof(struct qeth_hdr_tso);
 #endif
 #endif /* CONFIG_QETH_IPV6 */
 }
index 7ee1c06ed68a841af7ac49eeaa1d616681845b67..f94f1f25eec60a8e57ba9d311a90c47b2df58594 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.11 $)
+ * linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.13 $)
  *
  * Enhanced Device Driver Packing (EDDP) support for the qeth driver.
  *
@@ -8,7 +8,7 @@
  *
  *    Author(s): Thomas Spatzier <tspat@de.ibm.com>
  *
- *    $Revision: 1.11 $         $Date: 2005/03/24 09:04:18 $
+ *    $Revision: 1.13 $         $Date: 2005/05/04 20:19:18 $
  *
  */
 #include <linux/config.h>
@@ -85,7 +85,7 @@ void
 qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
 {
        struct qeth_eddp_context_reference *ref;
-
+       
        QETH_DBF_TEXT(trace, 6, "eddprctx");
        while (!list_empty(&buf->ctx_list)){
                ref = list_entry(buf->ctx_list.next,
@@ -139,7 +139,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
                                           "buffer!\n");
                                goto out;
                        }
-               }
+               }               
                /* check if the whole next skb fits into current buffer */
                if ((QETH_MAX_BUFFER_ELEMENTS(queue->card) -
                                        buf->next_element_to_fill)
@@ -152,7 +152,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
                         * and increment ctx's refcnt */
                        must_refcnt = 1;
                        continue;
-               }
+               }       
                if (must_refcnt){
                        must_refcnt = 0;
                        if (qeth_eddp_buf_ref_context(buf, ctx)){
@@ -202,40 +202,29 @@ out:
        return flush_cnt;
 }
 
-static inline int
-qeth_get_skb_data_len(struct sk_buff *skb)
-{
-       int len = skb->len;
-       int i;
-
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i)
-               len -= skb_shinfo(skb)->frags[i].size;
-       return len;
-}
-
 static inline void
 qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
-                             struct qeth_eddp_data *eddp)
+                             struct qeth_eddp_data *eddp, int data_len)
 {
        u8 *page;
        int page_remainder;
        int page_offset;
-       int hdr_len;
+       int pkt_len;
        struct qeth_eddp_element *element;
 
        QETH_DBF_TEXT(trace, 5, "eddpcrsh");
        page = ctx->pages[ctx->offset >> PAGE_SHIFT];
        page_offset = ctx->offset % PAGE_SIZE;
        element = &ctx->elements[ctx->num_elements];
-       hdr_len = eddp->nhl + eddp->thl;
+       pkt_len = eddp->nhl + eddp->thl + data_len;
        /* FIXME: layer2 and VLAN !!! */
        if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
-               hdr_len += ETH_HLEN;
+               pkt_len += ETH_HLEN;
        if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
-               hdr_len += VLAN_HLEN;
-       /* does complete header fit in current page ? */
+               pkt_len += VLAN_HLEN;
+       /* does complete packet fit in current page ? */
        page_remainder = PAGE_SIZE - page_offset;
-       if (page_remainder < (sizeof(struct qeth_hdr) + hdr_len)){
+       if (page_remainder < (sizeof(struct qeth_hdr) + pkt_len)){
                /* no -> go to start of next page */
                ctx->offset += page_remainder;
                page = ctx->pages[ctx->offset >> PAGE_SHIFT];
@@ -281,7 +270,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
        int left_in_frag;
        int copy_len;
        u8 *src;
-
+       
        QETH_DBF_TEXT(trace, 5, "eddpcdtc");
        if (skb_shinfo(eddp->skb)->nr_frags == 0) {
                memcpy(dst, eddp->skb->data + eddp->skb_offset, len);
@@ -292,7 +281,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
                while (len > 0) {
                        if (eddp->frag < 0) {
                                /* we're in skb->data */
-                               left_in_frag = qeth_get_skb_data_len(eddp->skb)
+                               left_in_frag = (eddp->skb->len - eddp->skb->data_len)
                                                - eddp->skb_offset;
                                src = eddp->skb->data + eddp->skb_offset;
                        } else {
@@ -424,7 +413,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
        struct tcphdr *tcph;
        int data_len;
        u32 hcsum;
-
+       
        QETH_DBF_TEXT(trace, 5, "eddpftcp");
        eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;
        tcph = eddp->skb->h.th;
@@ -464,7 +453,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
                else
                        hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len);
                /* fill the next segment into the context */
-               qeth_eddp_create_segment_hdrs(ctx, eddp);
+               qeth_eddp_create_segment_hdrs(ctx, eddp, data_len);
                qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum);
                if (eddp->skb_offset >= eddp->skb->len)
                        break;
@@ -474,13 +463,13 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
                eddp->th.tcp.h.seq += data_len;
        }
 }
-
+                          
 static inline int
 qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
                           struct sk_buff *skb, struct qeth_hdr *qhdr)
 {
        struct qeth_eddp_data *eddp = NULL;
-
+       
        QETH_DBF_TEXT(trace, 5, "eddpficx");
        /* create our segmentation headers and copy original headers */
        if (skb->protocol == ETH_P_IP)
@@ -520,7 +509,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
                         int hdr_len)
 {
        int skbs_per_page;
-
+       
        QETH_DBF_TEXT(trace, 5, "eddpcanp");
        /* can we put multiple skbs in one page? */
        skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
@@ -600,7 +589,7 @@ qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
                             struct qeth_hdr *qhdr)
 {
        struct qeth_eddp_context *ctx = NULL;
-
+       
        QETH_DBF_TEXT(trace, 5, "creddpct");
        if (skb->protocol == ETH_P_IP)
                ctx = qeth_eddp_create_context_generic(card, skb,
index 607b92542df6c3924cc5d7f8740928776661eb34..208127a5033ae707ffdb1168d2c0f7da979cab4d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/qeth_main.c ($Revision: 1.206 $)
+ * linux/drivers/s390/net/qeth_main.c ($Revision: 1.214 $)
  *
  * Linux on zSeries OSA Express and HiperSockets support
  *
@@ -12,7 +12,7 @@
  *                       Frank Pavlic (pavlic@de.ibm.com) and
  *                       Thomas Spatzier <tspat@de.ibm.com>
  *
- *    $Revision: 1.206 $        $Date: 2005/03/24 09:04:18 $
+ *    $Revision: 1.214 $        $Date: 2005/05/04 20:19:18 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -80,7 +80,7 @@ qeth_eyecatcher(void)
 #include "qeth_eddp.h"
 #include "qeth_tso.h"
 
-#define VERSION_QETH_C "$Revision: 1.206 $"
+#define VERSION_QETH_C "$Revision: 1.214 $"
 static const char *version = "qeth S/390 OSA-Express driver";
 
 /**
@@ -158,6 +158,9 @@ qeth_irq_tasklet(unsigned long);
 static int
 qeth_set_online(struct ccwgroup_device *);
 
+static int
+__qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode);
+
 static struct qeth_ipaddr *
 qeth_get_addr_buffer(enum qeth_prot_versions);
 
@@ -510,10 +513,10 @@ qeth_irq_tasklet(unsigned long data)
        wake_up(&card->wait_q);
 }
 
-static int qeth_stop_card(struct qeth_card *);
+static int qeth_stop_card(struct qeth_card *, int);
 
 static int
-qeth_set_offline(struct ccwgroup_device *cgdev)
+__qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode)
 {
        struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data;
        int rc = 0;
@@ -523,7 +526,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
        QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
 
        recover_flag = card->state;
-       if (qeth_stop_card(card) == -ERESTARTSYS){
+       if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){
                PRINT_WARN("Stopping card %s interrupted by user!\n",
                           CARD_BUS_ID(card));
                return -ERESTARTSYS;
@@ -539,6 +542,12 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
        return 0;
 }
 
+static int
+qeth_set_offline(struct ccwgroup_device *cgdev)
+{
+       return  __qeth_set_offline(cgdev, 0);
+}
+
 static int
 qeth_wait_for_threads(struct qeth_card *card, unsigned long threads);
 
@@ -953,8 +962,8 @@ qeth_recover(void *ptr)
        PRINT_WARN("Recovery of device %s started ...\n",
                   CARD_BUS_ID(card));
        card->use_hard_stop = 1;
-       qeth_set_offline(card->gdev);
-       rc = qeth_set_online(card->gdev);
+       __qeth_set_offline(card->gdev,1);
+       rc = __qeth_set_online(card->gdev,1);
        if (!rc)
                PRINT_INFO("Device %s successfully recovered!\n",
                           CARD_BUS_ID(card));
@@ -2152,9 +2161,15 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
        if (!skb_len)
                return NULL;
        if (card->options.fake_ll){
-               if (!(skb = qeth_get_skb(skb_len + QETH_FAKE_LL_LEN)))
-                       goto no_mem;
-               skb_pull(skb, QETH_FAKE_LL_LEN);
+               if(card->dev->type == ARPHRD_IEEE802_TR){
+                       if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR)))
+                               goto no_mem;
+                       skb_reserve(skb,QETH_FAKE_LL_LEN_TR);
+               } else {
+                       if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH)))
+                               goto no_mem;
+                       skb_reserve(skb,QETH_FAKE_LL_LEN_ETH);
+               }
        } else if (!(skb = qeth_get_skb(skb_len)))
                goto no_mem;
        data_ptr = element->addr + offset;
@@ -2229,14 +2244,68 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
 }
 
 static inline void
-qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
+qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
+                        struct qeth_hdr *hdr)
+{
+       struct trh_hdr *fake_hdr;
+       struct trllc *fake_llc;
+       struct iphdr *ip_hdr;
+
+       QETH_DBF_TEXT(trace,5,"skbfktr");
+       skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_TR;
+       /* this is a fake ethernet header */
+       fake_hdr = (struct trh_hdr *) skb->mac.raw;
+
+       /* the destination MAC address */
+       switch (skb->pkt_type){
+       case PACKET_MULTICAST:
+               switch (skb->protocol){
+#ifdef CONFIG_QETH_IPV6
+               case __constant_htons(ETH_P_IPV6):
+                       ndisc_mc_map((struct in6_addr *)
+                                    skb->data + QETH_FAKE_LL_V6_ADDR_POS,
+                                    fake_hdr->daddr, card->dev, 0);
+                       break;
+#endif /* CONFIG_QETH_IPV6 */
+               case __constant_htons(ETH_P_IP):
+                       ip_hdr = (struct iphdr *)skb->data;
+                       ip_tr_mc_map(ip_hdr->daddr, fake_hdr->daddr);
+                       break;
+               default:
+                       memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN);
+               }
+               break;
+       case PACKET_BROADCAST:
+               memset(fake_hdr->daddr, 0xff, TR_ALEN);
+               break;
+       default:
+               memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN);
+       }
+       /* the source MAC address */
+       if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
+               memcpy(fake_hdr->saddr, &hdr->hdr.l3.dest_addr[2], TR_ALEN);
+       else
+               memset(fake_hdr->saddr, 0, TR_ALEN);
+       fake_hdr->rcf=0;
+       fake_llc = (struct trllc*)&(fake_hdr->rcf);
+       fake_llc->dsap = EXTENDED_SAP;
+       fake_llc->ssap = EXTENDED_SAP;
+       fake_llc->llc  = UI_CMD;
+       fake_llc->protid[0] = 0;
+       fake_llc->protid[1] = 0;
+       fake_llc->protid[2] = 0;
+       fake_llc->ethertype = ETH_P_IP;
+}
+
+static inline void
+qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb,
                         struct qeth_hdr *hdr)
 {
        struct ethhdr *fake_hdr;
        struct iphdr *ip_hdr;
 
-       QETH_DBF_TEXT(trace,5,"skbfake");
-       skb->mac.raw = skb->data - QETH_FAKE_LL_LEN;
+       QETH_DBF_TEXT(trace,5,"skbfketh");
+       skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_ETH;
        /* this is a fake ethernet header */
        fake_hdr = (struct ethhdr *) skb->mac.raw;
 
@@ -2253,10 +2322,7 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
 #endif /* CONFIG_QETH_IPV6 */
                case __constant_htons(ETH_P_IP):
                        ip_hdr = (struct iphdr *)skb->data;
-                       if (card->dev->type == ARPHRD_IEEE802_TR)
-                               ip_tr_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
-                       else
-                               ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
+                       ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
                        break;
                default:
                        memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN);
@@ -2277,6 +2343,16 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
        fake_hdr->h_proto = skb->protocol;
 }
 
+static inline void
+qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
+                       struct qeth_hdr *hdr)
+{
+       if (card->dev->type == ARPHRD_IEEE802_TR)
+               qeth_rebuild_skb_fake_ll_tr(card, skb, hdr);
+       else
+               qeth_rebuild_skb_fake_ll_eth(card, skb, hdr);
+}
+
 static inline void
 qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb,
                      struct qeth_hdr *hdr)
@@ -3440,16 +3516,25 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
                     unsigned short type, void *daddr, void *saddr,
                     unsigned len)
 {
-       struct ethhdr *hdr;
+       if(dev->type == ARPHRD_IEEE802_TR){
+               struct trh_hdr *hdr;
+               hdr = (struct trh_hdr *)skb_push(skb, QETH_FAKE_LL_LEN_TR);
+               memcpy(hdr->saddr, dev->dev_addr, TR_ALEN);
+               memcpy(hdr->daddr, "FAKELL", TR_ALEN);
+               return QETH_FAKE_LL_LEN_TR;
+
+       } else {
+               struct ethhdr *hdr;
+               hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN_ETH);
+               memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN);
+               memcpy(hdr->h_dest, "FAKELL", ETH_ALEN);
+               if (type != ETH_P_802_3)
+                       hdr->h_proto = htons(type);
+               else
+                       hdr->h_proto = htons(len);
+               return QETH_FAKE_LL_LEN_ETH;
 
-        hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN);
-       memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN);
-        memcpy(hdr->h_dest, "FAKELL", ETH_ALEN);
-        if (type != ETH_P_802_3)
-                hdr->h_proto = htons(type);
-        else
-                hdr->h_proto = htons(len);
-       return QETH_FAKE_LL_LEN;
+       }
 }
 
 static inline int
@@ -3710,16 +3795,12 @@ static inline int
 qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
                 struct qeth_hdr **hdr, int ipv)
 {
-       int rc = 0;
 #ifdef CONFIG_QETH_VLAN
        u16 *tag;
 #endif
 
        QETH_DBF_TEXT(trace, 6, "prepskb");
 
-       rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
-       if (rc)
-               return rc;
 #ifdef CONFIG_QETH_VLAN
        if (card->vlangrp && vlan_tx_tag_present(*skb) &&
            ((ipv == 6) || card->options.layer2) ) {
@@ -3882,9 +3963,15 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
                        memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16);
                }
        } else { /* passthrough */
-               if (!memcmp(skb->data + sizeof(struct qeth_hdr),
+                if((skb->dev->type == ARPHRD_IEEE802_TR) &&
+                   !memcmp(skb->data + sizeof(struct qeth_hdr) + 
+                   sizeof(__u16), skb->dev->broadcast, 6)) {
+                       hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
+                                               QETH_HDR_PASSTHRU;
+               } else if (!memcmp(skb->data + sizeof(struct qeth_hdr),
                            skb->dev->broadcast, 6)) {   /* broadcast? */
-                       hdr->hdr.l3.flags = QETH_CAST_BROADCAST | QETH_HDR_PASSTHRU;
+                       hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
+                                               QETH_HDR_PASSTHRU;
                } else {
                        hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ?
                                QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU :
@@ -3893,68 +3980,30 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
        }
 }
 
-static inline void
-__qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer,
-                       int *next_element_to_fill)
-{
-       int length = skb->len;
-       struct skb_frag_struct *frag;
-       int fragno;
-       unsigned long addr;
-       int element;
-       int first_lap = 1;
-
-       fragno = skb_shinfo(skb)->nr_frags; /* start with last frag */
-       element = *next_element_to_fill + fragno;
-       while (length > 0) {
-               if (fragno > 0) {
-                       frag = &skb_shinfo(skb)->frags[fragno - 1];
-                       addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
-                               frag->page_offset;
-                       buffer->element[element].addr = (char *)addr;
-                       buffer->element[element].length = frag->size;
-                       length -= frag->size;
-                       if (first_lap)
-                               buffer->element[element].flags =
-                                   SBAL_FLAGS_LAST_FRAG;
-                       else
-                               buffer->element[element].flags =
-                                   SBAL_FLAGS_MIDDLE_FRAG;
-               } else {
-                       buffer->element[element].addr = skb->data;
-                       buffer->element[element].length = length;
-                       length = 0;
-                       buffer->element[element].flags =
-                               SBAL_FLAGS_FIRST_FRAG;
-               }
-               element--;
-               fragno--;
-               first_lap = 0;
-       }
-       *next_element_to_fill += skb_shinfo(skb)->nr_frags + 1;
-}
-
 static inline void
 __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
-                  int *next_element_to_fill)
+                  int is_tso, int *next_element_to_fill)
 {
        int length = skb->len;
        int length_here;
        int element;
        char *data;
-       int first_lap = 1;
+       int first_lap ;
 
        element = *next_element_to_fill;
        data = skb->data;
+       first_lap = (is_tso == 0 ? 1 : 0);
+
        while (length > 0) {
                /* length_here is the remaining amount of data in this page */
                length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
                if (length < length_here)
                        length_here = length;
+
                buffer->element[element].addr = data;
                buffer->element[element].length = length_here;
                length -= length_here;
-               if (!length){
+               if (!length) {
                        if (first_lap)
                                buffer->element[element].flags = 0;
                        else
@@ -3981,17 +4030,35 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue,
                 struct sk_buff *skb)
 {
        struct qdio_buffer *buffer;
-       int flush_cnt = 0;
+       struct qeth_hdr_tso *hdr;
+       int flush_cnt = 0, hdr_len, large_send = 0;
 
        QETH_DBF_TEXT(trace, 6, "qdfillbf");
+
        buffer = buf->buffer;
        atomic_inc(&skb->users);
        skb_queue_tail(&buf->skb_list, skb);
+
+       hdr  = (struct qeth_hdr_tso *) skb->data;
+       /*check first on TSO ....*/
+       if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) {
+               int element = buf->next_element_to_fill;
+
+               hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
+               /*fill first buffer entry only with header information */
+               buffer->element[element].addr = skb->data;
+               buffer->element[element].length = hdr_len;
+               buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
+               buf->next_element_to_fill++;
+               skb->data += hdr_len;
+               skb->len  -= hdr_len;
+               large_send = 1;
+       }
        if (skb_shinfo(skb)->nr_frags == 0)
-               __qeth_fill_buffer(skb, buffer,
+               __qeth_fill_buffer(skb, buffer, large_send,
                                   (int *)&buf->next_element_to_fill);
        else
-               __qeth_fill_buffer_frag(skb, buffer,
+               __qeth_fill_buffer_frag(skb, buffer, large_send,
                                        (int *)&buf->next_element_to_fill);
 
        if (!queue->do_pack) {
@@ -4183,6 +4250,25 @@ out:
        return rc;
 }
 
+static inline int
+qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb)
+{
+       int elements_needed = 0;
+
+        if (skb_shinfo(skb)->nr_frags > 0) {
+                elements_needed = (skb_shinfo(skb)->nr_frags + 1);
+       }
+        if (elements_needed == 0 )
+                elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
+                                        + skb->len) >> PAGE_SHIFT);
+        if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
+                PRINT_ERR("qeth_do_send_packet: invalid size of "
+                          "IP packet. Discarded.");
+                return 0;
+        }
+        return elements_needed;
+}
+
 static inline int
 qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
 {
@@ -4205,7 +4291,11 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
                                dev_kfree_skb_irq(skb);
                                return 0;
                        }
-                       skb_pull(skb, QETH_FAKE_LL_LEN);
+                       if(card->dev->type == ARPHRD_IEEE802_TR){
+                               skb_pull(skb, QETH_FAKE_LL_LEN_TR);
+                       } else {
+                               skb_pull(skb, QETH_FAKE_LL_LEN_ETH);
+                       }
                }
        }
        cast_type = qeth_get_cast_type(card, skb);
@@ -4221,19 +4311,25 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
        if (skb_shinfo(skb)->tso_size)
                large_send = card->options.large_send;
 
-       if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))){
-               QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
-               return rc;
-       }
        /*are we able to do TSO ? If so ,prepare and send it from here */
        if ((large_send == QETH_LARGE_SEND_TSO) &&
            (cast_type == RTN_UNSPEC)) {
-               rc = qeth_tso_send_packet(card, skb, queue,
-                                         ipv, cast_type);
-               goto do_statistics;
+               rc = qeth_tso_prepare_packet(card, skb, ipv, cast_type);
+               if (rc) {
+                       card->stats.tx_dropped++;
+                       card->stats.tx_errors++;
+                       dev_kfree_skb_any(skb);
+                       return NETDEV_TX_OK;
+               } 
+               elements_needed++;
+       } else {
+               if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) {
+                       QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
+                       return rc;
+               }
+               qeth_fill_header(card, hdr, skb, ipv, cast_type);
        }
 
-       qeth_fill_header(card, hdr, skb, ipv, cast_type);
        if (large_send == QETH_LARGE_SEND_EDDP) {
                ctx = qeth_eddp_create_context(card, skb, hdr);
                if (ctx == NULL) {
@@ -4241,7 +4337,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
                        return -EINVAL;
                }
        } else {
-               elements_needed = qeth_get_elements_no(card,(void*) hdr, skb);
+               elements_needed += qeth_get_elements_no(card,(void*) hdr, skb);
                if (!elements_needed)
                        return -EINVAL;
        }
@@ -4252,12 +4348,12 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
        else
                rc = qeth_do_send_packet_fast(card, queue, skb, hdr,
                                              elements_needed, ctx);
-do_statistics:
        if (!rc){
                card->stats.tx_packets++;
                card->stats.tx_bytes += skb->len;
 #ifdef CONFIG_QETH_PERF_STATS
-               if (skb_shinfo(skb)->tso_size) {
+               if (skb_shinfo(skb)->tso_size &&
+                  !(large_send == QETH_LARGE_SEND_NO)) {
                        card->perf_stats.large_send_bytes += skb->len;
                        card->perf_stats.large_send_cnt++;
                }
@@ -7154,7 +7250,7 @@ qeth_wait_for_threads(struct qeth_card *card, unsigned long threads)
 }
 
 static int
-qeth_stop_card(struct qeth_card *card)
+qeth_stop_card(struct qeth_card *card, int recovery_mode)
 {
        int rc = 0;
 
@@ -7167,9 +7263,13 @@ qeth_stop_card(struct qeth_card *card)
        if (card->read.state == CH_STATE_UP &&
            card->write.state == CH_STATE_UP &&
            (card->state == CARD_STATE_UP)) {
-               rtnl_lock();
-               dev_close(card->dev);
-               rtnl_unlock();
+               if(recovery_mode) {
+                       qeth_stop(card->dev);
+               } else {
+                       rtnl_lock();
+                       dev_close(card->dev);
+                       rtnl_unlock();
+               }
                if (!card->use_hard_stop) {
                        __u8 *mac = &card->dev->dev_addr[0];
                        rc = qeth_layer2_send_delmac(card, mac);
@@ -7341,13 +7441,17 @@ qeth_register_netdev(struct qeth_card *card)
 }
 
 static void
-qeth_start_again(struct qeth_card *card)
+qeth_start_again(struct qeth_card *card, int recovery_mode)
 {
        QETH_DBF_TEXT(setup ,2, "startag");
 
-       rtnl_lock();
-       dev_open(card->dev);
-       rtnl_unlock();
+       if(recovery_mode) {
+               qeth_open(card->dev);
+       } else {
+               rtnl_lock();
+               dev_open(card->dev);
+               rtnl_unlock();
+       }
        /* this also sets saved unicast addresses */
        qeth_set_multicast_list(card->dev);
 }
@@ -7404,7 +7508,7 @@ static void qeth_make_parameters_consistent(struct qeth_card *card)
 
 
 static int
-qeth_set_online(struct ccwgroup_device *gdev)
+__qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode)
 {
        struct qeth_card *card = gdev->dev.driver_data;
        int rc = 0;
@@ -7464,12 +7568,12 @@ qeth_set_online(struct ccwgroup_device *gdev)
  * we can also use this state for recovery purposes*/
        qeth_set_allowed_threads(card, 0xffffffff, 0);
        if (recover_flag == CARD_STATE_RECOVER)
-               qeth_start_again(card);
+               qeth_start_again(card, recovery_mode);
        qeth_notify_processes();
        return 0;
 out_remove:
        card->use_hard_stop = 1;
-       qeth_stop_card(card);
+       qeth_stop_card(card, 0);
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
@@ -7480,6 +7584,12 @@ out_remove:
        return -ENODEV;
 }
 
+static int
+qeth_set_online(struct ccwgroup_device *gdev)
+{
+       return __qeth_set_online(gdev, 0);
+}
+
 static struct ccw_device_id qeth_ids[] = {
        {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE},
        {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD},
diff --git a/drivers/s390/net/qeth_tso.c b/drivers/s390/net/qeth_tso.c
deleted file mode 100644 (file)
index c919762..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * linux/drivers/s390/net/qeth_tso.c ($Revision: 1.6 $)
- *
- * Header file for qeth TCP Segmentation Offload support.
- *
- * Copyright 2004 IBM Corporation
- *
- *    Author(s): Frank Pavlic <pavlic@de.ibm.com>
- *
- *    $Revision: 1.6 $  $Date: 2005/03/24 09:04:18 $
- *
- */
-
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <net/ip6_checksum.h>
-#include "qeth.h"
-#include "qeth_mpc.h"
-#include "qeth_tso.h"
-
-/**
- * skb already partially prepared
- * classic qdio header in skb->data
- * */
-static inline struct qeth_hdr_tso *
-qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
-{
-       int rc = 0;
-
-       QETH_DBF_TEXT(trace, 5, "tsoprsk");
-       rc = qeth_realloc_headroom(card, skb,sizeof(struct qeth_hdr_ext_tso));
-       if (rc)
-               return NULL;
-
-       return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_ext_tso));
-}
-
-/**
- * fill header for a TSO packet
- */
-static inline void
-qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
-{
-       struct qeth_hdr_tso *hdr;
-       struct tcphdr *tcph;
-       struct iphdr *iph;
-
-       QETH_DBF_TEXT(trace, 5, "tsofhdr");
-
-       hdr  = (struct qeth_hdr_tso *) skb->data;
-       iph  = skb->nh.iph;
-       tcph = skb->h.th;
-       /*fix header to TSO values ...*/
-       hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
-       /*set values which are fix for the first approach ...*/
-       hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
-       hdr->ext.imb_hdr_no  = 1;
-       hdr->ext.hdr_type    = 1;
-       hdr->ext.hdr_version = 1;
-       hdr->ext.hdr_len     = 28;
-       /*insert non-fix values */
-       hdr->ext.mss = skb_shinfo(skb)->tso_size;
-       hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
-       hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
-                                      sizeof(struct qeth_hdr_tso));
-}
-
-/**
- * change some header values as requested by hardware
- */
-static inline void
-qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
-{
-       struct iphdr *iph;
-       struct ipv6hdr *ip6h;
-       struct tcphdr *tcph;
-
-       iph  = skb->nh.iph;
-       ip6h = skb->nh.ipv6h;
-       tcph = skb->h.th;
-
-       tcph->check = 0;
-       if (skb->protocol == ETH_P_IPV6) {
-               ip6h->payload_len = 0;
-               tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
-                                              0, IPPROTO_TCP, 0);
-               return;
-       }
-       /*OSA want us to set these values ...*/
-       tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-                                        0, IPPROTO_TCP, 0);
-       iph->tot_len = 0;
-       iph->check = 0;
-}
-
-static inline struct qeth_hdr_tso *
-qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb,
-                       int ipv, int cast_type)
-{
-       struct qeth_hdr_tso *hdr;
-       int rc = 0;
-
-       QETH_DBF_TEXT(trace, 5, "tsoprep");
-
-       /*get headroom for tso qdio header */
-       hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb);
-       if (hdr == NULL) {
-               QETH_DBF_TEXT_(trace, 4, "2err%d", rc);
-               return NULL;
-       }
-       memset(hdr, 0, sizeof(struct qeth_hdr_tso));
-       /*fill first 32 bytes of  qdio header as used
-        *FIXME: TSO has two struct members
-        * with different names but same size
-        * */
-       qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type);
-       qeth_tso_fill_header(card, skb);
-       qeth_tso_set_tcpip_header(card, skb);
-       return hdr;
-}
-
-static inline int
-qeth_tso_get_queue_buffer(struct qeth_qdio_out_q *queue)
-{
-       struct qeth_qdio_out_buffer *buffer;
-       int flush_cnt = 0;
-
-       QETH_DBF_TEXT(trace, 5, "tsobuf");
-
-       /* force to non-packing*/
-       if (queue->do_pack)
-               queue->do_pack = 0;
-       buffer = &queue->bufs[queue->next_buf_to_fill];
-       /* get a new buffer if current is already in use*/
-       if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
-           (buffer->next_element_to_fill > 0)) {
-               atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
-               queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
-                                         QDIO_MAX_BUFFERS_PER_Q;
-               flush_cnt++;
-       }
-       return flush_cnt;
-}
-
-static inline void
-__qeth_tso_fill_buffer_frag(struct qeth_qdio_out_buffer *buf,
-                         struct sk_buff *skb)
-{
-       struct skb_frag_struct *frag;
-       struct qdio_buffer *buffer;
-       int fragno, cnt, element;
-       unsigned long addr;
-
-        QETH_DBF_TEXT(trace, 6, "tsfilfrg");
-
-       /*initialize variables ...*/
-       fragno = skb_shinfo(skb)->nr_frags;
-       buffer = buf->buffer;
-       element = buf->next_element_to_fill;
-       /*fill buffer elements .....*/
-       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++;
-       }
-       buf->next_element_to_fill = element;
-}
-
-static inline int
-qeth_tso_fill_buffer(struct qeth_qdio_out_buffer *buf,
-                    struct sk_buff *skb)
-{
-        int length, length_here, element;
-        int hdr_len;
-       struct qdio_buffer *buffer;
-       struct qeth_hdr_tso *hdr;
-       char *data;
-
-        QETH_DBF_TEXT(trace, 3, "tsfilbuf");
-
-       /*increment user count and queue skb ...*/
-        atomic_inc(&skb->users);
-        skb_queue_tail(&buf->skb_list, skb);
-
-       /*initialize all variables...*/
-        buffer = buf->buffer;
-       hdr = (struct qeth_hdr_tso *)skb->data;
-       hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
-       data = skb->data + hdr_len;
-       length = skb->len - hdr_len;
-        element = buf->next_element_to_fill;
-       /*fill first buffer entry only with header information */
-       buffer->element[element].addr = skb->data;
-       buffer->element[element].length = hdr_len;
-       buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
-       buf->next_element_to_fill++;
-
-       if (skb_shinfo(skb)->nr_frags > 0) {
-                 __qeth_tso_fill_buffer_frag(buf, skb);
-                 goto out;
-        }
-
-       /*start filling buffer entries ...*/
-        element++;
-        while (length > 0) {
-                /* length_here is the remaining amount of data in this page */
-               length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
-               if (length < length_here)
-                        length_here = length;
-                buffer->element[element].addr = data;
-                buffer->element[element].length = length_here;
-                length -= length_here;
-                if (!length)
-                        buffer->element[element].flags =
-                                SBAL_FLAGS_LAST_FRAG;
-                 else
-                         buffer->element[element].flags =
-                                 SBAL_FLAGS_MIDDLE_FRAG;
-                data += length_here;
-                element++;
-        }
-        /*set the buffer to primed  ...*/
-        buf->next_element_to_fill = element;
-out:
-       atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
-        return 1;
-}
-
-int
-qeth_tso_send_packet(struct qeth_card *card, struct sk_buff *skb,
-                    struct qeth_qdio_out_q *queue, int ipv, int cast_type)
-{
-       int flush_cnt = 0;
-       struct qeth_hdr_tso *hdr;
-       struct qeth_qdio_out_buffer *buffer;
-        int start_index;
-
-       QETH_DBF_TEXT(trace, 3, "tsosend");
-
-       if (!(hdr = qeth_tso_prepare_packet(card, skb, ipv, cast_type)))
-               return -ENOMEM;
-       /*check if skb fits in one SBAL ...*/
-       if (!(qeth_get_elements_no(card, (void*)hdr, skb)))
-               return -EINVAL;
-       /*lock queue, force switching to non-packing and send it ...*/
-       while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
-                                       QETH_OUT_Q_LOCKED,
-                                       &queue->state));
-        start_index = queue->next_buf_to_fill;
-        buffer = &queue->bufs[queue->next_buf_to_fill];
-       /*check if card is too busy ...*/
-       if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
-               card->stats.tx_dropped++;
-               goto out;
-       }
-       /*let's force to non-packing and get a new SBAL*/
-       flush_cnt += qeth_tso_get_queue_buffer(queue);
-       buffer = &queue->bufs[queue->next_buf_to_fill];
-       if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
-               card->stats.tx_dropped++;
-               goto out;
-       }
-       flush_cnt += qeth_tso_fill_buffer(buffer, skb);
-       queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
-                                  QDIO_MAX_BUFFERS_PER_Q;
-out:
-       atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
-       if (flush_cnt)
-               qeth_flush_buffers(queue, 0, start_index, flush_cnt);
-       /*do some statistics */
-       card->stats.tx_packets++;
-       card->stats.tx_bytes += skb->len;
-       return 0;
-}
index 83504dee3f57d9d72ee963772a3d63429bd729c7..ad33e6f466f1bd819547f687e5b9e719a6c19f5e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.4 $)
+ * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.7 $)
  *
  * Header file for qeth TCP Segmentation Offload support.
  *
  *
  *    Author(s): Frank Pavlic <pavlic@de.ibm.com>
  *
- *    $Revision: 1.4 $  $Date: 2005/03/24 09:04:18 $
+ *    $Revision: 1.7 $  $Date: 2005/05/04 20:19:18 $
  *
  */
 #ifndef __QETH_TSO_H__
 #define __QETH_TSO_H__
 
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
+#include "qeth.h"
+#include "qeth_mpc.h"
 
-extern int
-qeth_tso_send_packet(struct qeth_card *, struct sk_buff *,
-                    struct qeth_qdio_out_q *, int , int);
 
-struct qeth_hdr_ext_tso {
-        __u16 hdr_tot_len;
-        __u8  imb_hdr_no;
-        __u8  reserved;
-        __u8  hdr_type;
-        __u8  hdr_version;
-        __u16 hdr_len;
-        __u32 payload_len;
-        __u16 mss;
-        __u16 dg_hdr_len;
-        __u8  padding[16];
-} __attribute__ ((packed));
+static inline struct qeth_hdr_tso *
+qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
+{
+       QETH_DBF_TEXT(trace, 5, "tsoprsk");
+       return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_tso));
+}
+
+/**
+ * fill header for a TSO packet
+ */
+static inline void
+qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
+{
+       struct qeth_hdr_tso *hdr;
+       struct tcphdr *tcph;
+       struct iphdr *iph;
+
+       QETH_DBF_TEXT(trace, 5, "tsofhdr");
+
+       hdr  = (struct qeth_hdr_tso *) skb->data;
+       iph  = skb->nh.iph;
+       tcph = skb->h.th;
+       /*fix header to TSO values ...*/
+       hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
+       /*set values which are fix for the first approach ...*/
+       hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
+       hdr->ext.imb_hdr_no  = 1;
+       hdr->ext.hdr_type    = 1;
+       hdr->ext.hdr_version = 1;
+       hdr->ext.hdr_len     = 28;
+       /*insert non-fix values */
+       hdr->ext.mss = skb_shinfo(skb)->tso_size;
+       hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
+       hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
+                                      sizeof(struct qeth_hdr_tso));
+}
+
+/**
+ * change some header values as requested by hardware
+ */
+static inline void
+qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
+{
+       struct iphdr *iph;
+       struct ipv6hdr *ip6h;
+       struct tcphdr *tcph;
 
-struct qeth_hdr_tso {
-        struct qeth_hdr hdr;   /*hdr->hdr.l3.xxx*/
-       struct qeth_hdr_ext_tso ext;
-} __attribute__ ((packed));
+       iph  = skb->nh.iph;
+       ip6h = skb->nh.ipv6h;
+       tcph = skb->h.th;
 
-/*some helper functions*/
+       tcph->check = 0;
+       if (skb->protocol == ETH_P_IPV6) {
+               ip6h->payload_len = 0;
+               tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+                                              0, IPPROTO_TCP, 0);
+               return;
+       }
+       /*OSA want us to set these values ...*/
+       tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                        0, IPPROTO_TCP, 0);
+       iph->tot_len = 0;
+       iph->check = 0;
+}
 
 static inline int
-qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb)
+qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb,
+                       int ipv, int cast_type)
+{
+       struct qeth_hdr_tso *hdr;
+
+       QETH_DBF_TEXT(trace, 5, "tsoprep");
+
+       hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb);
+       if (hdr == NULL) {
+               QETH_DBF_TEXT(trace, 4, "tsoperr");
+               return -ENOMEM;
+       }
+       memset(hdr, 0, sizeof(struct qeth_hdr_tso));
+       /*fill first 32 bytes of  qdio header as used
+        *FIXME: TSO has two struct members
+        * with different names but same size
+        * */
+       qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type);
+       qeth_tso_fill_header(card, skb);
+       qeth_tso_set_tcpip_header(card, skb);
+       return 0;
+}
+
+static inline void
+__qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer,
+                       int is_tso, int *next_element_to_fill)
 {
-       int elements_needed = 0;
-
-       if (skb_shinfo(skb)->nr_frags > 0)
-               elements_needed = (skb_shinfo(skb)->nr_frags + 1);
-       if (elements_needed == 0 )
-               elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
-                                       + skb->len) >> PAGE_SHIFT);
-       if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
-               PRINT_ERR("qeth_do_send_packet: invalid size of "
-                         "IP packet. Discarded.");
-               return 0;
+       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;
+       if ( (dlen = (skb->len - skb->data_len)) ) {
+               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++;
        }
-       return elements_needed;
+       *next_element_to_fill = element;
 }
 #endif /* __QETH_TSO_H__ */