include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / s390 / net / qeth_core_main.c
index 4a2ac0c..3ba738b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/net/qeth_core_main.c
  *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007, 2009
  *    Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
  *              Frank Pavlic <fpavlic@de.ibm.com>,
  *              Thomas Spatzier <tspat@de.ibm.com>,
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/ip.h>
-#include <linux/ipv6.h>
 #include <linux/tcp.h>
 #include <linux/mii.h>
 #include <linux/kthread.h>
+#include <linux/slab.h>
 
 #include <asm/ebcdic.h>
 #include <asm/io.h>
-#include <asm/s390_rdev.h>
 
 #include "qeth_core.h"
-#include "qeth_core_offl.h"
 
 struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = {
        /* define dbf - Name, Pages, Areas, Maxlen, Level, View, Handle */
@@ -272,45 +270,7 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
        card->qdio.init_pool.buf_count = bufcnt;
        return qeth_alloc_buffer_pool(card);
 }
-
-int qeth_set_large_send(struct qeth_card *card,
-               enum qeth_large_send_types type)
-{
-       int rc = 0;
-
-       if (card->dev == NULL) {
-               card->options.large_send = type;
-               return 0;
-       }
-       if (card->state == CARD_STATE_UP)
-               netif_tx_disable(card->dev);
-       card->options.large_send = type;
-       switch (card->options.large_send) {
-       case QETH_LARGE_SEND_EDDP:
-               card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
-                                       NETIF_F_HW_CSUM;
-               break;
-       case QETH_LARGE_SEND_TSO:
-               if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
-                       card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
-                                               NETIF_F_HW_CSUM;
-               } else {
-                       card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
-                                               NETIF_F_HW_CSUM);
-                       card->options.large_send = QETH_LARGE_SEND_NO;
-                       rc = -EOPNOTSUPP;
-               }
-               break;
-       default: /* includes QETH_LARGE_SEND_NO */
-               card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
-                                       NETIF_F_HW_CSUM);
-               break;
-       }
-       if (card->state == CARD_STATE_UP)
-               netif_wake_queue(card->dev);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(qeth_set_large_send);
+EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool);
 
 static int qeth_issue_next_read(struct qeth_card *card)
 {
@@ -392,8 +352,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
        if (IS_IPA(iob->data)) {
                cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
                if (IS_IPA_REPLY(cmd)) {
-                       if (cmd->hdr.command < IPA_CMD_SETCCID ||
-                           cmd->hdr.command > IPA_CMD_MODCCID)
+                       if (cmd->hdr.command != IPA_CMD_SETCCID &&
+                           cmd->hdr.command != IPA_CMD_DELCCID &&
+                           cmd->hdr.command != IPA_CMD_MODCCID &&
+                           cmd->hdr.command != IPA_CMD_SET_DIAG_ASS)
                                qeth_issue_ipa_msg(cmd,
                                                cmd->hdr.return_code, card);
                        return cmd;
@@ -576,7 +538,8 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel,
                        dev_err(&card->gdev->dev,
                                "The qeth device is not configured "
                                "for the OSI layer required by z/VM\n");
-               qeth_schedule_recovery(card);
+               else
+                       qeth_schedule_recovery(card);
                goto out;
        }
 
@@ -934,8 +897,8 @@ out:
        return;
 }
 
-static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
-                struct qeth_qdio_out_buffer *buf)
+static void __qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
+                struct qeth_qdio_out_buffer *buf, unsigned int qeth_skip_skb)
 {
        int i;
        struct sk_buff *skb;
@@ -944,13 +907,14 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
        if (buf->buffer->element[0].flags & 0x40)
                atomic_dec(&queue->set_pci_flags_count);
 
-       skb = skb_dequeue(&buf->skb_list);
-       while (skb) {
-               atomic_dec(&skb->users);
-               dev_kfree_skb_any(skb);
+       if (!qeth_skip_skb) {
                skb = skb_dequeue(&buf->skb_list);
+               while (skb) {
+                       atomic_dec(&skb->users);
+                       dev_kfree_skb_any(skb);
+                       skb = skb_dequeue(&buf->skb_list);
+               }
        }
-       qeth_eddp_buf_release_contexts(buf);
        for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) {
                if (buf->buffer->element[i].addr && buf->is_header[i])
                        kmem_cache_free(qeth_core_header_cache,
@@ -960,10 +924,17 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
                buf->buffer->element[i].addr = NULL;
                buf->buffer->element[i].flags = 0;
        }
+       buf->buffer->element[15].flags = 0;
        buf->next_element_to_fill = 0;
        atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
 }
 
+static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
+               struct qeth_qdio_out_buffer *buf)
+{
+       __qeth_clear_output_buffer(queue, buf, 0);
+}
+
 void qeth_clear_qdio_buffers(struct qeth_card *card)
 {
        int i, j;
@@ -1078,6 +1049,7 @@ static void qeth_set_intial_options(struct qeth_card *card)
        card->options.add_hhlen = DEFAULT_ADD_HHLEN;
        card->options.performance_stats = 0;
        card->options.rx_sg_cb = QETH_RX_SG_CB;
+       card->options.isolation = ISOLATION_MODE_NONE;
 }
 
 static int qeth_do_start_thread(struct qeth_card *card, unsigned long thread)
@@ -1133,11 +1105,6 @@ static int qeth_setup_card(struct qeth_card *card)
        card->thread_running_mask = 0;
        INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread);
        INIT_LIST_HEAD(&card->ip_list);
-       card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
-       if (!card->ip_tbd_list) {
-               QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
-               return -ENOMEM;
-       }
        INIT_LIST_HEAD(card->ip_tbd_list);
        INIT_LIST_HEAD(&card->cmd_waiter_list);
        init_waitqueue_head(&card->wait_q);
@@ -1157,8 +1124,9 @@ static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr)
 {
        struct qeth_card *card = container_of(slr, struct qeth_card,
                                        qeth_service_level);
-       seq_printf(m, "qeth: %s firmware level %s\n", CARD_BUS_ID(card),
-                       card->info.mcl_level);
+       if (card->info.mcl_level[0])
+               seq_printf(m, "qeth: %s firmware level %s\n",
+                       CARD_BUS_ID(card), card->info.mcl_level);
 }
 
 static struct qeth_card *qeth_alloc_card(void)
@@ -1168,21 +1136,30 @@ static struct qeth_card *qeth_alloc_card(void)
        QETH_DBF_TEXT(SETUP, 2, "alloccrd");
        card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL);
        if (!card)
-               return NULL;
+               goto out;
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
-       if (qeth_setup_channel(&card->read)) {
-               kfree(card);
-               return NULL;
-       }
-       if (qeth_setup_channel(&card->write)) {
-               qeth_clean_channel(&card->read);
-               kfree(card);
-               return NULL;
+       card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+       if (!card->ip_tbd_list) {
+               QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
+               goto out_card;
        }
+       if (qeth_setup_channel(&card->read))
+               goto out_ip;
+       if (qeth_setup_channel(&card->write))
+               goto out_channel;
        card->options.layer2 = -1;
        card->qeth_service_level.seq_print = qeth_core_sl_print;
        register_service_level(&card->qeth_service_level);
        return card;
+
+out_channel:
+       qeth_clean_channel(&card->read);
+out_ip:
+       kfree(card->ip_tbd_list);
+out_card:
+       kfree(card);
+out:
+       return NULL;
 }
 
 static int qeth_determine_card_type(struct qeth_card *card)
@@ -1385,26 +1362,29 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
        return ret;
 }
 
-static int qeth_get_unitaddr(struct qeth_card *card)
+static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd)
 {
-       int length;
-       char *prcd;
-       int rc;
-
-       QETH_DBF_TEXT(SETUP, 2, "getunit");
-       rc = qeth_read_conf_data(card, (void **) &prcd, &length);
-       if (rc) {
-               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
-                       dev_name(&card->gdev->dev), rc);
-               return rc;
-       }
+       QETH_DBF_TEXT(SETUP, 2, "cfgunit");
        card->info.chpid = prcd[30];
        card->info.unit_addr2 = prcd[31];
        card->info.cula = prcd[63];
        card->info.guestlan = ((prcd[0x10] == _ascebc['V']) &&
                               (prcd[0x11] == _ascebc['M']));
-       kfree(prcd);
-       return 0;
+}
+
+static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd)
+{
+       QETH_DBF_TEXT(SETUP, 2, "cfgblkt");
+
+       if (prcd[74] == 0xF0 && prcd[75] == 0xF0 && prcd[76] == 0xF5) {
+               card->info.blkt.time_total = 250;
+               card->info.blkt.inter_packet = 5;
+               card->info.blkt.inter_packet_jumbo = 15;
+       } else {
+               card->info.blkt.time_total = 0;
+               card->info.blkt.inter_packet = 0;
+               card->info.blkt.inter_packet_jumbo = 0;
+       }
 }
 
 static void qeth_init_tokens(struct qeth_card *card)
@@ -1684,7 +1664,7 @@ int qeth_send_control_data(struct qeth_card *card, int len,
        int rc;
        unsigned long flags;
        struct qeth_reply *reply = NULL;
-       unsigned long timeout;
+       unsigned long timeout, event_timeout;
        struct qeth_ipa_cmd *cmd;
 
        QETH_DBF_TEXT(TRACE, 2, "sendctl");
@@ -1709,9 +1689,10 @@ int qeth_send_control_data(struct qeth_card *card, int len,
        qeth_prepare_control_data(card, len, iob);
 
        if (IS_IPA(iob->data))
-               timeout = jiffies + QETH_IPA_TIMEOUT;
+               event_timeout = QETH_IPA_TIMEOUT;
        else
-               timeout = jiffies + QETH_TIMEOUT;
+               event_timeout = QETH_TIMEOUT;
+       timeout = jiffies + event_timeout;
 
        QETH_DBF_TEXT(TRACE, 6, "noirqpnd");
        spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
@@ -1739,7 +1720,7 @@ int qeth_send_control_data(struct qeth_card *card, int len,
        if ((cmd->hdr.command == IPA_CMD_SETIP) &&
            (cmd->hdr.prot_version == QETH_PROT_IPV4)) {
                if (!wait_event_timeout(reply->wait_q,
-                   atomic_read(&reply->received), timeout))
+                   atomic_read(&reply->received), event_timeout))
                        goto time_err;
        } else {
                while (!atomic_read(&reply->received)) {
@@ -2602,8 +2583,8 @@ int qeth_query_setadapterparms(struct qeth_card *card)
 }
 EXPORT_SYMBOL_GPL(qeth_query_setadapterparms);
 
-int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
-               const char *dbftext)
+int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf,
+               unsigned int qdio_error, const char *dbftext)
 {
        if (qdio_error) {
                QETH_DBF_TEXT(TRACE, 2, dbftext);
@@ -2613,7 +2594,11 @@ int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
                QETH_DBF_TEXT_(QERR, 2, " F14=%02X",
                               buf->element[14].flags & 0xff);
                QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error);
-               return 1;
+               if ((buf->element[15].flags & 0xff) == 0x12) {
+                       card->stats.rx_dropped++;
+                       return 0;
+               } else
+                       return 1;
        }
        return 0;
 }
@@ -2687,40 +2672,28 @@ static int qeth_handle_send_error(struct qeth_card *card,
                struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err)
 {
        int sbalf15 = buffer->buffer->element[15].flags & 0xff;
-       int cc = qdio_err & 3;
 
        QETH_DBF_TEXT(TRACE, 6, "hdsnderr");
-       qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr");
-       switch (cc) {
-       case 0:
-               if (qdio_err) {
-                       QETH_DBF_TEXT(TRACE, 1, "lnkfail");
-                       QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
-                       QETH_DBF_TEXT_(TRACE, 1, "%04x %02x",
-                                      (u16)qdio_err, (u8)sbalf15);
-                       return QETH_SEND_ERROR_LINK_FAILURE;
-               }
-               return QETH_SEND_ERROR_NONE;
-       case 2:
-               if (qdio_err & QDIO_ERROR_SIGA_BUSY) {
-                       QETH_DBF_TEXT(TRACE, 1, "SIGAcc2B");
-                       QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
-                       return QETH_SEND_ERROR_KICK_IT;
+       if (card->info.type == QETH_CARD_TYPE_IQD) {
+               if (sbalf15 == 0) {
+                       qdio_err = 0;
+               } else {
+                       qdio_err = 1;
                }
-               if ((sbalf15 >= 15) && (sbalf15 <= 31))
-                       return QETH_SEND_ERROR_RETRY;
-               return QETH_SEND_ERROR_LINK_FAILURE;
-               /* look at qdio_error and sbalf 15 */
-       case 1:
-               QETH_DBF_TEXT(TRACE, 1, "SIGAcc1");
-               QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
-               return QETH_SEND_ERROR_LINK_FAILURE;
-       case 3:
-       default:
-               QETH_DBF_TEXT(TRACE, 1, "SIGAcc3");
-               QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
-               return QETH_SEND_ERROR_KICK_IT;
        }
+       qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qouterr");
+
+       if (!qdio_err)
+               return QETH_SEND_ERROR_NONE;
+
+       if ((sbalf15 >= 15) && (sbalf15 <= 31))
+               return QETH_SEND_ERROR_RETRY;
+
+       QETH_DBF_TEXT(TRACE, 1, "lnkfail");
+       QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
+       QETH_DBF_TEXT_(TRACE, 1, "%04x %02x",
+                      (u16)qdio_err, (u8)sbalf15);
+       return QETH_SEND_ERROR_LINK_FAILURE;
 }
 
 /*
@@ -2840,6 +2813,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
                }
        }
 
+       queue->sync_iqdio_error = 0;
        queue->card->dev->trans_start = jiffies;
        if (queue->card->options.performance_stats) {
                queue->card->perf_stats.outbound_do_qdio_cnt++;
@@ -2855,11 +2829,19 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
                queue->card->perf_stats.outbound_do_qdio_time +=
                        qeth_get_micros() -
                        queue->card->perf_stats.outbound_do_qdio_start_time;
+       if (rc > 0) {
+               if (!(rc & QDIO_ERROR_SIGA_BUSY))
+                       queue->sync_iqdio_error = rc & 3;
+       }
        if (rc) {
+               queue->card->stats.tx_errors += count;
+               /* ignore temporary SIGA errors without busy condition */
+               if (rc == QDIO_ERROR_SIGA_TARGET)
+                       return;
                QETH_DBF_TEXT(TRACE, 2, "flushbuf");
                QETH_DBF_TEXT_(TRACE, 2, " err%d", rc);
                QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_DDEV_ID(queue->card));
-               queue->card->stats.tx_errors += count;
+
                /* this must not happen under normal circumstances. if it
                 * happens something is really wrong -> recover */
                qeth_schedule_recovery(queue->card);
@@ -2918,6 +2900,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
        struct qeth_qdio_out_q *queue = card->qdio.out_qs[__queue];
        struct qeth_qdio_out_buffer *buffer;
        int i;
+       unsigned qeth_send_err;
 
        QETH_DBF_TEXT(TRACE, 6, "qdouhdl");
        if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
@@ -2934,14 +2917,9 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
        }
        for (i = first_element; i < (first_element + count); ++i) {
                buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
-               /*we only handle the KICK_IT error by doing a recovery */
-               if (qeth_handle_send_error(card, buffer, qdio_error)
-                               == QETH_SEND_ERROR_KICK_IT){
-                       netif_stop_queue(card->dev);
-                       qeth_schedule_recovery(card);
-                       return;
-               }
-               qeth_clear_output_buffer(queue, buffer);
+               qeth_send_err = qeth_handle_send_error(card, buffer, qdio_error);
+               __qeth_clear_output_buffer(queue, buffer,
+                       (qeth_send_err == QETH_SEND_ERROR_RETRY) ? 1 : 0);
        }
        atomic_sub(count, &queue->used_buffers);
        /* check if we need to do something on this outbound queue */
@@ -2955,55 +2933,6 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
 }
 EXPORT_SYMBOL_GPL(qeth_qdio_output_handler);
 
-int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
-{
-       int cast_type = RTN_UNSPEC;
-
-       if (card->info.type == QETH_CARD_TYPE_OSN)
-               return cast_type;
-
-       if (skb->dst && skb->dst->neighbour) {
-               cast_type = skb->dst->neighbour->type;
-               if ((cast_type == RTN_BROADCAST) ||
-                   (cast_type == RTN_MULTICAST) ||
-                   (cast_type == RTN_ANYCAST))
-                       return cast_type;
-               else
-                       return RTN_UNSPEC;
-       }
-       /* try something else */
-       if (skb->protocol == ETH_P_IPV6)
-               return (skb_network_header(skb)[24] == 0xff) ?
-                               RTN_MULTICAST : 0;
-       else if (skb->protocol == ETH_P_IP)
-               return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ?
-                               RTN_MULTICAST : 0;
-       /* ... */
-       if (!memcmp(skb->data, skb->dev->broadcast, 6))
-               return RTN_BROADCAST;
-       else {
-               u16 hdr_mac;
-
-               hdr_mac = *((u16 *)skb->data);
-               /* tr multicast? */
-               switch (card->info.link_type) {
-               case QETH_LINK_TYPE_HSTR:
-               case QETH_LINK_TYPE_LANE_TR:
-                       if ((hdr_mac == QETH_TR_MAC_NC) ||
-                           (hdr_mac == QETH_TR_MAC_C))
-                               return RTN_MULTICAST;
-                       break;
-               /* eth or so multicast? */
-               default:
-               if ((hdr_mac == QETH_ETH_MAC_V4) ||
-                           (hdr_mac == QETH_ETH_MAC_V6))
-                               return RTN_MULTICAST;
-               }
-       }
-       return cast_type;
-}
-EXPORT_SYMBOL_GPL(qeth_get_cast_type);
-
 int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
                        int ipv, int cast_type)
 {
@@ -3181,12 +3110,13 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
 int qeth_do_send_packet_fast(struct qeth_card *card,
                struct qeth_qdio_out_q *queue, struct sk_buff *skb,
                struct qeth_hdr *hdr, int elements_needed,
-               struct qeth_eddp_context *ctx, int offset, int hd_len)
+               int offset, int hd_len)
 {
        struct qeth_qdio_out_buffer *buffer;
-       int buffers_needed = 0;
-       int flush_cnt = 0;
+       struct sk_buff *skb1;
+       struct qeth_skb_data *retry_ctrl;
        int index;
+       int rc;
 
        /* spin until we get the queue ... */
        while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
@@ -3200,26 +3130,29 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
         */
        if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY)
                goto out;
-       if (ctx == NULL)
-               queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
+       queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
                                          QDIO_MAX_BUFFERS_PER_Q;
-       else {
-               buffers_needed = qeth_eddp_check_buffers_for_context(queue,
-                                                                       ctx);
-               if (buffers_needed < 0)
-                       goto out;
-               queue->next_buf_to_fill =
-                       (queue->next_buf_to_fill + buffers_needed) %
-                       QDIO_MAX_BUFFERS_PER_Q;
-       }
        atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
-       if (ctx == NULL) {
-               qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len);
-               qeth_flush_buffers(queue, index, 1);
-       } else {
-               flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index);
-               WARN_ON(buffers_needed != flush_cnt);
-               qeth_flush_buffers(queue, index, flush_cnt);
+       qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len);
+       qeth_flush_buffers(queue, index, 1);
+       if (queue->sync_iqdio_error == 2) {
+               skb1 = skb_dequeue(&buffer->skb_list);
+               while (skb1) {
+                       atomic_dec(&skb1->users);
+                       skb1 = skb_dequeue(&buffer->skb_list);
+               }
+               retry_ctrl = (struct qeth_skb_data *) &skb->cb[16];
+               if (retry_ctrl->magic != QETH_SKB_MAGIC) {
+                       retry_ctrl->magic = QETH_SKB_MAGIC;
+                       retry_ctrl->count = 0;
+               }
+               if (retry_ctrl->count < QETH_SIGA_CC2_RETRIES) {
+                       retry_ctrl->count++;
+                       rc = dev_queue_xmit(skb);
+               } else {
+                       dev_kfree_skb_any(skb);
+                       QETH_DBF_TEXT(QERR, 2, "qrdrop");
+               }
        }
        return 0;
 out:
@@ -3230,7 +3163,7 @@ EXPORT_SYMBOL_GPL(qeth_do_send_packet_fast);
 
 int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
                struct sk_buff *skb, struct qeth_hdr *hdr,
-               int elements_needed, struct qeth_eddp_context *ctx)
+               int elements_needed)
 {
        struct qeth_qdio_out_buffer *buffer;
        int start_index;
@@ -3256,53 +3189,32 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
        qeth_switch_to_packing_if_needed(queue);
        if (queue->do_pack) {
                do_pack = 1;
-               if (ctx == NULL) {
-                       /* does packet fit in current buffer? */
-                       if ((QETH_MAX_BUFFER_ELEMENTS(card) -
-                           buffer->next_element_to_fill) < elements_needed) {
-                               /* ... no -> set state PRIMED */
-                               atomic_set(&buffer->state,
-                                       QETH_QDIO_BUF_PRIMED);
-                               flush_count++;
-                               queue->next_buf_to_fill =
-                                       (queue->next_buf_to_fill + 1) %
-                                       QDIO_MAX_BUFFERS_PER_Q;
-                               buffer = &queue->bufs[queue->next_buf_to_fill];
-                               /* we did a step forward, so check buffer state
-                                * again */
-                               if (atomic_read(&buffer->state) !=
-                                               QETH_QDIO_BUF_EMPTY){
-                                       qeth_flush_buffers(queue, start_index,
+               /* does packet fit in current buffer? */
+               if ((QETH_MAX_BUFFER_ELEMENTS(card) -
+                   buffer->next_element_to_fill) < elements_needed) {
+                       /* ... no -> set state PRIMED */
+                       atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
+                       flush_count++;
+                       queue->next_buf_to_fill =
+                               (queue->next_buf_to_fill + 1) %
+                               QDIO_MAX_BUFFERS_PER_Q;
+                       buffer = &queue->bufs[queue->next_buf_to_fill];
+                       /* we did a step forward, so check buffer state
+                        * again */
+                       if (atomic_read(&buffer->state) !=
+                           QETH_QDIO_BUF_EMPTY) {
+                               qeth_flush_buffers(queue, start_index,
                                                           flush_count);
-                                       atomic_set(&queue->state,
+                               atomic_set(&queue->state,
                                                QETH_OUT_Q_UNLOCKED);
-                                       return -EBUSY;
-                               }
+                               return -EBUSY;
                        }
-               } else {
-                       /* check if we have enough elements (including following
-                        * free buffers) to handle eddp context */
-                       if (qeth_eddp_check_buffers_for_context(queue, ctx)
-                               < 0) {
-                               rc = -EBUSY;
-                               goto out;
-                       }
-               }
-       }
-       if (ctx == NULL)
-               tmp = qeth_fill_buffer(queue, buffer, skb, hdr, -1, 0);
-       else {
-               tmp = qeth_eddp_fill_buffer(queue, ctx,
-                                               queue->next_buf_to_fill);
-               if (tmp < 0) {
-                       rc = -EBUSY;
-                       goto out;
                }
        }
+       tmp = qeth_fill_buffer(queue, buffer, skb, hdr, -1, 0);
        queue->next_buf_to_fill = (queue->next_buf_to_fill + tmp) %
                                  QDIO_MAX_BUFFERS_PER_Q;
        flush_count += tmp;
-out:
        if (flush_count)
                qeth_flush_buffers(queue, start_index, flush_count);
        else if (!atomic_read(&queue->set_pci_flags_count))
@@ -3457,10 +3369,161 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card)
 }
 EXPORT_SYMBOL_GPL(qeth_setadpparms_change_macaddr);
 
+static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
+               struct qeth_reply *reply, unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd;
+       struct qeth_set_access_ctrl *access_ctrl_req;
+       int rc;
+
+       QETH_DBF_TEXT(TRACE, 4, "setaccb");
+
+       cmd = (struct qeth_ipa_cmd *) data;
+       access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
+       QETH_DBF_TEXT_(SETUP, 2, "setaccb");
+       QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
+       QETH_DBF_TEXT_(SETUP, 2, "rc=%d",
+               cmd->data.setadapterparms.hdr.return_code);
+       switch (cmd->data.setadapterparms.hdr.return_code) {
+       case SET_ACCESS_CTRL_RC_SUCCESS:
+       case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED:
+       case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED:
+       {
+               card->options.isolation = access_ctrl_req->subcmd_code;
+               if (card->options.isolation == ISOLATION_MODE_NONE) {
+                       dev_info(&card->gdev->dev,
+                           "QDIO data connection isolation is deactivated\n");
+               } else {
+                       dev_info(&card->gdev->dev,
+                           "QDIO data connection isolation is activated\n");
+               }
+               QETH_DBF_MESSAGE(3, "OK:SET_ACCESS_CTRL(%s, %d)==%d\n",
+                       card->gdev->dev.kobj.name,
+                       access_ctrl_req->subcmd_code,
+                       cmd->data.setadapterparms.hdr.return_code);
+               rc = 0;
+               break;
+       }
+       case SET_ACCESS_CTRL_RC_NOT_SUPPORTED:
+       {
+               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n",
+                       card->gdev->dev.kobj.name,
+                       access_ctrl_req->subcmd_code,
+                       cmd->data.setadapterparms.hdr.return_code);
+               dev_err(&card->gdev->dev, "Adapter does not "
+                       "support QDIO data connection isolation\n");
+
+               /* ensure isolation mode is "none" */
+               card->options.isolation = ISOLATION_MODE_NONE;
+               rc = -EOPNOTSUPP;
+               break;
+       }
+       case SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER:
+       {
+               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n",
+                       card->gdev->dev.kobj.name,
+                       access_ctrl_req->subcmd_code,
+                       cmd->data.setadapterparms.hdr.return_code);
+               dev_err(&card->gdev->dev,
+                       "Adapter is dedicated. "
+                       "QDIO data connection isolation not supported\n");
+
+               /* ensure isolation mode is "none" */
+               card->options.isolation = ISOLATION_MODE_NONE;
+               rc = -EOPNOTSUPP;
+               break;
+       }
+       case SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF:
+       {
+               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n",
+                       card->gdev->dev.kobj.name,
+                       access_ctrl_req->subcmd_code,
+                       cmd->data.setadapterparms.hdr.return_code);
+               dev_err(&card->gdev->dev,
+                       "TSO does not permit QDIO data connection isolation\n");
+
+               /* ensure isolation mode is "none" */
+               card->options.isolation = ISOLATION_MODE_NONE;
+               rc = -EPERM;
+               break;
+       }
+       default:
+       {
+               /* this should never happen */
+               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d"
+                       "==UNKNOWN\n",
+                       card->gdev->dev.kobj.name,
+                       access_ctrl_req->subcmd_code,
+                       cmd->data.setadapterparms.hdr.return_code);
+
+               /* ensure isolation mode is "none" */
+               card->options.isolation = ISOLATION_MODE_NONE;
+               rc = 0;
+               break;
+       }
+       }
+       qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
+       return rc;
+}
+
+static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
+               enum qeth_ipa_isolation_modes isolation)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+       struct qeth_set_access_ctrl *access_ctrl_req;
+
+       QETH_DBF_TEXT(TRACE, 4, "setacctl");
+
+       QETH_DBF_TEXT_(SETUP, 2, "setacctl");
+       QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
+
+       iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_ACCESS_CONTROL,
+                                  sizeof(struct qeth_ipacmd_setadpparms_hdr) +
+                                  sizeof(struct qeth_set_access_ctrl));
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+       access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
+       access_ctrl_req->subcmd_code = isolation;
+
+       rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_set_access_ctrl_cb,
+                              NULL);
+       QETH_DBF_TEXT_(SETUP, 2, "rc=%d", rc);
+       return rc;
+}
+
+int qeth_set_access_ctrl_online(struct qeth_card *card)
+{
+       int rc = 0;
+
+       QETH_DBF_TEXT(TRACE, 4, "setactlo");
+
+       if (card->info.type == QETH_CARD_TYPE_OSAE &&
+           qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) {
+               rc = qeth_setadpparms_set_access_ctrl(card,
+                       card->options.isolation);
+               if (rc) {
+                       QETH_DBF_MESSAGE(3,
+                               "IPA(SET_ACCESS_CTRL,%s,%d) sent failed",
+                               card->gdev->dev.kobj.name,
+                               rc);
+               }
+       } else if (card->options.isolation != ISOLATION_MODE_NONE) {
+               card->options.isolation = ISOLATION_MODE_NONE;
+
+               dev_err(&card->gdev->dev, "Adapter does not "
+                       "support QDIO data connection isolation\n");
+               rc = -EOPNOTSUPP;
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(qeth_set_access_ctrl_online);
+
 void qeth_tx_timeout(struct net_device *dev)
 {
        struct qeth_card *card;
 
+       QETH_DBF_TEXT(TRACE, 4, "txtimeo");
        card = dev->ml_priv;
        card->stats.tx_errors++;
        qeth_schedule_recovery(card);
@@ -3742,9 +3805,6 @@ static int qeth_qdio_establish(struct qeth_card *card)
        init_data.input_handler          = card->discipline.input_handler;
        init_data.output_handler         = card->discipline.output_handler;
        init_data.int_parm               = (unsigned long) card;
-       init_data.flags                  = QDIO_INBOUND_0COPY_SBALS |
-                                          QDIO_OUTBOUND_0COPY_SBALS |
-                                          QDIO_USE_OUTBOUND_PCIS;
        init_data.input_sbal_addr_array  = (void **) in_sbal_ptrs;
        init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;
 
@@ -3799,60 +3859,39 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev,
 
 int qeth_core_hardsetup_card(struct qeth_card *card)
 {
-       struct qdio_ssqd_desc *ssqd;
-       int retries = 3;
-       int mpno = 0;
+       int retries = 0;
        int rc;
 
        QETH_DBF_TEXT(SETUP, 2, "hrdsetup");
        atomic_set(&card->force_alloc_skb, 0);
 retry:
-       if (retries < 3) {
+       if (retries)
                QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
                        dev_name(&card->gdev->dev));
-               ccw_device_set_offline(CARD_DDEV(card));
-               ccw_device_set_offline(CARD_WDEV(card));
-               ccw_device_set_offline(CARD_RDEV(card));
-               ccw_device_set_online(CARD_RDEV(card));
-               ccw_device_set_online(CARD_WDEV(card));
-               ccw_device_set_online(CARD_DDEV(card));
-       }
+       ccw_device_set_offline(CARD_DDEV(card));
+       ccw_device_set_offline(CARD_WDEV(card));
+       ccw_device_set_offline(CARD_RDEV(card));
+       rc = ccw_device_set_online(CARD_RDEV(card));
+       if (rc)
+               goto retriable;
+       rc = ccw_device_set_online(CARD_WDEV(card));
+       if (rc)
+               goto retriable;
+       rc = ccw_device_set_online(CARD_DDEV(card));
+       if (rc)
+               goto retriable;
        rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
+retriable:
        if (rc == -ERESTARTSYS) {
                QETH_DBF_TEXT(SETUP, 2, "break1");
                return rc;
        } else if (rc) {
                QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
-               if (--retries < 0)
+               if (++retries > 3)
                        goto out;
                else
                        goto retry;
        }
-
-       rc = qeth_get_unitaddr(card);
-       if (rc) {
-               QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
-               return rc;
-       }
-
-       ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL);
-       if (!ssqd) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd);
-       if (rc == 0)
-               mpno = ssqd->pcnt;
-       kfree(ssqd);
-
-       if (mpno)
-               mpno = min(mpno - 1, QETH_MAX_PORTNO);
-       if (card->info.portno > mpno) {
-               QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d"
-                       "\n.", CARD_BUS_ID(card), card->info.portno);
-               rc = -ENODEV;
-               goto out;
-       }
        qeth_init_tokens(card);
        qeth_init_func_level(card);
        rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb);
@@ -3936,7 +3975,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
        struct qdio_buffer_element *element = *__element;
        int offset = *__offset;
        struct sk_buff *skb = NULL;
-       int skb_len;
+       int skb_len = 0;
        void *data_ptr;
        int data_len;
        int headroom = 0;
@@ -3955,20 +3994,24 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
        *hdr = element->addr + offset;
 
        offset += sizeof(struct qeth_hdr);
-       if (card->options.layer2) {
-               if (card->info.type == QETH_CARD_TYPE_OSN) {
-                       skb_len = (*hdr)->hdr.osn.pdu_length;
-                       headroom = sizeof(struct qeth_hdr);
-               } else {
-                       skb_len = (*hdr)->hdr.l2.pkt_length;
-               }
-       } else {
+       switch ((*hdr)->hdr.l2.id) {
+       case QETH_HEADER_TYPE_LAYER2:
+               skb_len = (*hdr)->hdr.l2.pkt_length;
+               break;
+       case QETH_HEADER_TYPE_LAYER3:
                skb_len = (*hdr)->hdr.l3.length;
                if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
                    (card->info.link_type == QETH_LINK_TYPE_HSTR))
                        headroom = TR_HLEN;
                else
                        headroom = ETH_HLEN;
+               break;
+       case QETH_HEADER_TYPE_OSN:
+               skb_len = (*hdr)->hdr.osn.pdu_length;
+               headroom = sizeof(struct qeth_hdr);
+               break;
+       default:
+               break;
        }
 
        if (!skb_len)
@@ -4123,6 +4166,41 @@ void qeth_core_free_discipline(struct qeth_card *card)
        card->discipline.ccwgdriver = NULL;
 }
 
+static void qeth_determine_capabilities(struct qeth_card *card)
+{
+       int rc;
+       int length;
+       char *prcd;
+
+       QETH_DBF_TEXT(SETUP, 2, "detcapab");
+       rc = ccw_device_set_online(CARD_DDEV(card));
+       if (rc) {
+               QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+               goto out;
+       }
+
+
+       rc = qeth_read_conf_data(card, (void **) &prcd, &length);
+       if (rc) {
+               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
+                       dev_name(&card->gdev->dev), rc);
+               QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+               goto out_offline;
+       }
+       qeth_configure_unitaddr(card, prcd);
+       qeth_configure_blkt_default(card, prcd);
+       kfree(prcd);
+
+       rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
+       if (rc)
+               QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+
+out_offline:
+       ccw_device_set_offline(CARD_DDEV(card));
+out:
+       return;
+}
+
 static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card;
@@ -4188,6 +4266,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
        write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
        list_add_tail(&card->list, &qeth_core_card_list.list);
        write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
+
+       qeth_determine_capabilities(card);
        return 0;
 
 err_card:
@@ -4259,6 +4339,50 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev)
                card->discipline.ccwgdriver->shutdown(gdev);
 }
 
+static int qeth_core_prepare(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->prepare)
+               return card->discipline.ccwgdriver->prepare(gdev);
+       return 0;
+}
+
+static void qeth_core_complete(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->complete)
+               card->discipline.ccwgdriver->complete(gdev);
+}
+
+static int qeth_core_freeze(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->freeze)
+               return card->discipline.ccwgdriver->freeze(gdev);
+       return 0;
+}
+
+static int qeth_core_thaw(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->thaw)
+               return card->discipline.ccwgdriver->thaw(gdev);
+       return 0;
+}
+
+static int qeth_core_restore(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->restore)
+               return card->discipline.ccwgdriver->restore(gdev);
+       return 0;
+}
+
 static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
        .owner = THIS_MODULE,
        .name = "qeth",
@@ -4268,6 +4392,11 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
        .set_online = qeth_core_set_online,
        .set_offline = qeth_core_set_offline,
        .shutdown = qeth_core_shutdown,
+       .prepare = qeth_core_prepare,
+       .complete = qeth_core_complete,
+       .freeze = qeth_core_freeze,
+       .thaw = qeth_core_thaw,
+       .restore = qeth_core_restore,
 };
 
 static ssize_t
@@ -4321,13 +4450,20 @@ static struct {
 /* 30 */{"tx count"},
        {"tx do_QDIO time"},
        {"tx do_QDIO count"},
+       {"tx csum"},
+       {"tx lin"},
 };
 
-int qeth_core_get_stats_count(struct net_device *dev)
+int qeth_core_get_sset_count(struct net_device *dev, int stringset)
 {
-       return (sizeof(qeth_ethtool_stats_keys) / ETH_GSTRING_LEN);
+       switch (stringset) {
+       case ETH_SS_STATS:
+               return (sizeof(qeth_ethtool_stats_keys) / ETH_GSTRING_LEN);
+       default:
+               return -EINVAL;
+       }
 }
-EXPORT_SYMBOL_GPL(qeth_core_get_stats_count);
+EXPORT_SYMBOL_GPL(qeth_core_get_sset_count);
 
 void qeth_core_get_ethtool_stats(struct net_device *dev,
                struct ethtool_stats *stats, u64 *data)
@@ -4372,6 +4508,8 @@ void qeth_core_get_ethtool_stats(struct net_device *dev,
        data[30] = card->perf_stats.outbound_cnt;
        data[31] = card->perf_stats.outbound_do_qdio_time;
        data[32] = card->perf_stats.outbound_do_qdio_cnt;
+       data[33] = card->perf_stats.tx_csum;
+       data[34] = card->perf_stats.tx_lin;
 }
 EXPORT_SYMBOL_GPL(qeth_core_get_ethtool_stats);
 
@@ -4518,7 +4656,7 @@ static int __init qeth_core_init(void)
                                &driver_attr_group);
        if (rc)
                goto driver_err;
-       qeth_core_root_dev = s390_root_dev_register("qeth");
+       qeth_core_root_dev = root_device_register("qeth");
        rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0;
        if (rc)
                goto register_err;
@@ -4532,7 +4670,7 @@ static int __init qeth_core_init(void)
 
        return 0;
 slab_err:
-       s390_root_dev_unregister(qeth_core_root_dev);
+       root_device_unregister(qeth_core_root_dev);
 register_err:
        driver_remove_file(&qeth_core_ccwgroup_driver.driver,
                           &driver_attr_group);
@@ -4550,7 +4688,7 @@ out_err:
 
 static void __exit qeth_core_exit(void)
 {
-       s390_root_dev_unregister(qeth_core_root_dev);
+       root_device_unregister(qeth_core_root_dev);
        driver_remove_file(&qeth_core_ccwgroup_driver.driver,
                           &driver_attr_group);
        ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver);