]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/s390/net/qeth_l3_main.c
s390/qeth: remove a redundant check for card->dev
[linux.git] / drivers / s390 / net / qeth_l3_main.c
index df34bff4ac31ba18c62380c6e13a312fdc1d8213..13d77957404c317307984bc99434c6986480579d 100644 (file)
@@ -40,7 +40,6 @@
 
 
 static int qeth_l3_set_offline(struct ccwgroup_device *);
-static int qeth_l3_stop(struct net_device *);
 static void qeth_l3_set_rx_mode(struct net_device *dev);
 static int qeth_l3_register_addr_entry(struct qeth_card *,
                struct qeth_ipaddr *);
@@ -254,8 +253,7 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
                } else
                        rc = qeth_l3_register_addr_entry(card, addr);
 
-               if (!rc || (rc == IPA_RC_DUPLICATE_IP_ADDRESS) ||
-                               (rc == IPA_RC_LAN_OFFLINE)) {
+               if (!rc || rc == -EADDRINUSE || rc == -ENETDOWN) {
                        addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
                        if (addr->ref_counter < 1) {
                                qeth_l3_deregister_addr_entry(card, addr);
@@ -339,10 +337,28 @@ static void qeth_l3_recover_ip(struct qeth_card *card)
 
 }
 
+static int qeth_l3_setdelip_cb(struct qeth_card *card, struct qeth_reply *reply,
+                              unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
+
+       switch (cmd->hdr.return_code) {
+       case IPA_RC_SUCCESS:
+               return 0;
+       case IPA_RC_DUPLICATE_IP_ADDRESS:
+               return -EADDRINUSE;
+       case IPA_RC_MC_ADDR_NOT_FOUND:
+               return -ENOENT;
+       case IPA_RC_LAN_OFFLINE:
+               return -ENETDOWN;
+       default:
+               return -EIO;
+       }
+}
+
 static int qeth_l3_send_setdelmc(struct qeth_card *card,
                        struct qeth_ipaddr *addr, int ipacmd)
 {
-       int rc;
        struct qeth_cmd_buffer *iob;
        struct qeth_ipa_cmd *cmd;
 
@@ -359,9 +375,7 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card,
        else
                memcpy(&cmd->data.setdelipm.ip4, &addr->u.a4.addr, 4);
 
-       rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
-
-       return rc;
+       return qeth_send_ipa_cmd(card, iob, qeth_l3_setdelip_cb, NULL);
 }
 
 static void qeth_l3_fill_netmask(u8 *netmask, unsigned int len)
@@ -423,7 +437,7 @@ static int qeth_l3_send_setdelip(struct qeth_card *card,
                cmd->data.setdelip4.flags = flags;
        }
 
-       return qeth_send_ipa_cmd(card, iob, NULL, NULL);
+       return qeth_send_ipa_cmd(card, iob, qeth_l3_setdelip_cb, NULL);
 }
 
 static int qeth_l3_send_setrouting(struct qeth_card *card,
@@ -943,12 +957,13 @@ static int qeth_l3_start_ipassists(struct qeth_card *card)
 static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card,
                struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
 
-       cmd = (struct qeth_ipa_cmd *) data;
-       if (cmd->hdr.return_code == 0)
-               ether_addr_copy(card->dev->dev_addr,
-                               cmd->data.create_destroy_addr.unique_id);
+       if (cmd->hdr.return_code)
+               return -EIO;
+
+       ether_addr_copy(card->dev->dev_addr,
+                       cmd->data.create_destroy_addr.unique_id);
        return 0;
 }
 
@@ -976,19 +991,18 @@ static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card)
 static int qeth_l3_get_unique_id_cb(struct qeth_card *card,
                struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
 
-       cmd = (struct qeth_ipa_cmd *) data;
-       if (cmd->hdr.return_code == 0)
+       if (cmd->hdr.return_code == 0) {
                card->info.unique_id = *((__u16 *)
                                &cmd->data.create_destroy_addr.unique_id[6]);
-       else {
-               card->info.unique_id =  UNIQUE_ID_IF_CREATE_ADDR_FAILED |
-                                       UNIQUE_ID_NOT_BY_CARD;
-               dev_warn(&card->gdev->dev, "The network adapter failed to "
-                       "generate a unique ID\n");
+               return 0;
        }
-       return 0;
+
+       card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED |
+                              UNIQUE_ID_NOT_BY_CARD;
+       dev_warn(&card->gdev->dev, "The network adapter failed to generate a unique ID\n");
+       return -EIO;
 }
 
 static int qeth_l3_get_unique_id(struct qeth_card *card)
@@ -1071,7 +1085,7 @@ qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
                                 cmd->data.diagass.action, CARD_DEVID(card));
        }
 
-       return 0;
+       return rc ? -EIO : 0;
 }
 
 static int
@@ -1281,10 +1295,6 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
 
        QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
 
-       if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
-               QETH_CARD_TEXT(card, 3, "kidREC");
-               return 0;
-       }
        clear_bit(vid, card->active_vlans);
        qeth_l3_set_rx_mode(dev);
        return 0;
@@ -1305,12 +1315,11 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
                                ip_eth_mc_map(ip_hdr(skb)->daddr, tg_addr);
                        else
                                ipv6_eth_mc_map(&ipv6_hdr(skb)->daddr, tg_addr);
-
-                       card->stats.multicast++;
+                       QETH_CARD_STAT_INC(card, rx_multicast);
                        break;
                case QETH_CAST_BROADCAST:
                        ether_addr_copy(tg_addr, card->dev->broadcast);
-                       card->stats.multicast++;
+                       QETH_CARD_STAT_INC(card, rx_multicast);
                        break;
                default:
                        if (card->options.sniffer)
@@ -1391,13 +1400,13 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
                }
                work_done++;
                budget--;
-               card->stats.rx_packets++;
-               card->stats.rx_bytes += len;
+               QETH_CARD_STAT_INC(card, rx_packets);
+               QETH_CARD_STAT_ADD(card, rx_bytes, len);
        }
        return work_done;
 }
 
-static void qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
+static void qeth_l3_stop_card(struct qeth_card *card)
 {
        QETH_DBF_TEXT(SETUP, 2, "stopcard");
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
@@ -1408,16 +1417,8 @@ static void qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
                qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
        if (card->read.state == CH_STATE_UP &&
            card->write.state == CH_STATE_UP &&
-           (card->state == CARD_STATE_UP)) {
-               if (recovery_mode)
-                       qeth_l3_stop(card->dev);
-               else {
-                       rtnl_lock();
-                       dev_close(card->dev);
-                       rtnl_unlock();
-               }
+           card->state == CARD_STATE_UP)
                card->state = CARD_STATE_SOFTSETUP;
-       }
        if (card->state == CARD_STATE_SOFTSETUP) {
                qeth_l3_clear_ip_htable(card, 1);
                qeth_clear_ipacmd_list(card);
@@ -1475,9 +1476,7 @@ static void qeth_l3_set_rx_mode(struct net_device *dev)
        int i, rc;
 
        QETH_CARD_TEXT(card, 3, "setmulti");
-       if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
-           (card->state != CARD_STATE_UP))
-               return;
+
        if (!card->options.sniffer) {
                spin_lock_bh(&card->mclock);
 
@@ -1488,14 +1487,14 @@ static void qeth_l3_set_rx_mode(struct net_device *dev)
                        switch (addr->disp_flag) {
                        case QETH_DISP_ADDR_DELETE:
                                rc = qeth_l3_deregister_addr_entry(card, addr);
-                               if (!rc || rc == IPA_RC_MC_ADDR_NOT_FOUND) {
+                               if (!rc || rc == -ENOENT) {
                                        hash_del(&addr->hnode);
                                        kfree(addr);
                                }
                                break;
                        case QETH_DISP_ADDR_ADD:
                                rc = qeth_l3_register_addr_entry(card, addr);
-                               if (rc && rc != IPA_RC_LAN_OFFLINE) {
+                               if (rc && rc != -ENETDOWN) {
                                        hash_del(&addr->hnode);
                                        kfree(addr);
                                        break;
@@ -1516,7 +1515,7 @@ static void qeth_l3_set_rx_mode(struct net_device *dev)
        qeth_l3_handle_promisc_mode(card);
 }
 
-static int qeth_l3_arp_makerc(int rc)
+static int qeth_l3_arp_makerc(u16 rc)
 {
        switch (rc) {
        case IPA_RC_SUCCESS:
@@ -1533,8 +1532,18 @@ static int qeth_l3_arp_makerc(int rc)
        }
 }
 
+static int qeth_l3_arp_cmd_cb(struct qeth_card *card, struct qeth_reply *reply,
+                             unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
+
+       qeth_setassparms_cb(card, reply, data);
+       return qeth_l3_arp_makerc(cmd->hdr.return_code);
+}
+
 static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
 {
+       struct qeth_cmd_buffer *iob;
        int rc;
 
        QETH_CARD_TEXT(card, 3, "arpstnoe");
@@ -1549,13 +1558,19 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
        if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
                return -EOPNOTSUPP;
        }
-       rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
-                                         IPA_CMD_ASS_ARP_SET_NO_ENTRIES,
-                                         no_entries);
+
+       iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
+                                      IPA_CMD_ASS_ARP_SET_NO_ENTRIES, 4,
+                                      QETH_PROT_IPV4);
+       if (!iob)
+               return -ENOMEM;
+
+       __ipa_cmd(iob)->data.setassparms.data.flags_32bit = (u32) no_entries;
+       rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_cmd_cb, NULL);
        if (rc)
                QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on device %x: %#x\n",
                                 CARD_DEVID(card), rc);
-       return qeth_l3_arp_makerc(rc);
+       return rc;
 }
 
 static __u32 get_arp_entry_size(struct qeth_card *card,
@@ -1606,7 +1621,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
        struct qeth_ipa_cmd *cmd;
        struct qeth_arp_query_data *qdata;
        struct qeth_arp_query_info *qinfo;
-       int i;
        int e;
        int entrybytes_done;
        int stripped_bytes;
@@ -1620,13 +1634,13 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
        if (cmd->hdr.return_code) {
                QETH_CARD_TEXT(card, 4, "arpcberr");
                QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
-               return 0;
+               return qeth_l3_arp_makerc(cmd->hdr.return_code);
        }
        if (cmd->data.setassparms.hdr.return_code) {
                cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
                QETH_CARD_TEXT(card, 4, "setaperr");
                QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
-               return 0;
+               return qeth_l3_arp_makerc(cmd->hdr.return_code);
        }
        qdata = &cmd->data.setassparms.data.query_arp;
        QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries);
@@ -1653,9 +1667,9 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
                        break;
 
                if ((qinfo->udata_len - qinfo->udata_offset) < esize) {
-                       QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
-                       cmd->hdr.return_code = IPA_RC_ENOMEM;
-                       goto out_error;
+                       QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOSPC);
+                       memset(qinfo->udata, 0, 4);
+                       return -ENOSPC;
                }
 
                memcpy(qinfo->udata + qinfo->udata_offset,
@@ -1678,10 +1692,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
        memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2);
        QETH_CARD_TEXT_(card, 4, "rc%i", 0);
        return 0;
-out_error:
-       i = 0;
-       memcpy(qinfo->udata, &i, 4);
-       return 0;
 }
 
 static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
@@ -1703,13 +1713,11 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
                return -ENOMEM;
        cmd = __ipa_cmd(iob);
        cmd->data.setassparms.data.query_arp.request_bits = 0x000F;
-       rc = qeth_send_control_data(card,
-                                   QETH_SETASS_BASE_LEN + QETH_ARP_CMD_LEN,
-                                   iob, qeth_l3_arp_query_cb, qinfo);
+       rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_query_cb, qinfo);
        if (rc)
                QETH_DBF_MESSAGE(2, "Error while querying ARP cache on device %x: %#x\n",
                                 CARD_DEVID(card), rc);
-       return qeth_l3_arp_makerc(rc);
+       return rc;
 }
 
 static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
@@ -1791,16 +1799,16 @@ static int qeth_l3_arp_modify_entry(struct qeth_card *card,
        cmd_entry = &__ipa_cmd(iob)->data.setassparms.data.arp_entry;
        ether_addr_copy(cmd_entry->macaddr, entry->macaddr);
        memcpy(cmd_entry->ipaddr, entry->ipaddr, 4);
-       rc = qeth_send_ipa_cmd(card, iob, qeth_setassparms_cb, NULL);
+       rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_cmd_cb, NULL);
        if (rc)
                QETH_DBF_MESSAGE(2, "Could not modify (cmd: %#x) ARP entry on device %x: %#x\n",
                                 arp_cmd, CARD_DEVID(card), rc);
-
-       return qeth_l3_arp_makerc(rc);
+       return rc;
 }
 
 static int qeth_l3_arp_flush_cache(struct qeth_card *card)
 {
+       struct qeth_cmd_buffer *iob;
        int rc;
 
        QETH_CARD_TEXT(card, 3, "arpflush");
@@ -1815,12 +1823,18 @@ static int qeth_l3_arp_flush_cache(struct qeth_card *card)
        if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
                return -EOPNOTSUPP;
        }
-       rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
-                                         IPA_CMD_ASS_ARP_FLUSH_CACHE, 0);
+
+       iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
+                                      IPA_CMD_ASS_ARP_FLUSH_CACHE, 0,
+                                      QETH_PROT_IPV4);
+       if (!iob)
+               return -ENOMEM;
+
+       rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_cmd_cb, NULL);
        if (rc)
                QETH_DBF_MESSAGE(2, "Could not flush ARP cache on device %x: %#x\n",
                                 CARD_DEVID(card), rc);
-       return qeth_l3_arp_makerc(rc);
+       return rc;
 }
 
 static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1922,12 +1936,13 @@ static u8 qeth_l3_cast_type_to_flag(int cast_type)
        return QETH_CAST_UNICAST;
 }
 
-static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
-                               struct sk_buff *skb, int ipv, int cast_type,
-                               unsigned int data_len)
+static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
+                               struct qeth_hdr *hdr, struct sk_buff *skb,
+                               int ipv, int cast_type, unsigned int data_len)
 {
        struct qeth_hdr_layer3 *l3_hdr = &hdr->hdr.l3;
        struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
+       struct qeth_card *card = queue->card;
 
        hdr->hdr.l3.length = data_len;
 
@@ -1949,8 +1964,7 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
                        /* some HW requires combined L3+L4 csum offload: */
                        if (ipv == 4)
                                hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ;
-                       if (card->options.performance_stats)
-                               card->perf_stats.tx_csum++;
+                       QETH_TXQ_STAT_INC(queue, skbs_csum);
                }
        }
 
@@ -2051,6 +2065,8 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
        int tx_bytes = skb->len;
        int rc;
 
+       queue = qeth_get_tx_queue(card, skb, ipv, cast_type);
+
        if (IS_IQD(card)) {
                if (card->options.sniffer)
                        goto tx_drop;
@@ -2061,19 +2077,13 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
        }
 
        if (card->state != CARD_STATE_UP) {
-               card->stats.tx_carrier_errors++;
+               QETH_TXQ_STAT_INC(queue, tx_carrier_errors);
                goto tx_drop;
        }
 
        if (cast_type == RTN_BROADCAST && !card->info.broadcast_capable)
                goto tx_drop;
 
-       queue = qeth_get_tx_queue(card, skb, ipv, cast_type);
-
-       if (card->options.performance_stats) {
-               card->perf_stats.outbound_cnt++;
-               card->perf_stats.outbound_start_time = qeth_get_micros();
-       }
        netif_stop_queue(dev);
 
        if (ipv == 4 || IS_IQD(card))
@@ -2083,11 +2093,8 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
                               qeth_l3_fill_header);
 
        if (!rc) {
-               card->stats.tx_packets++;
-               card->stats.tx_bytes += tx_bytes;
-               if (card->options.performance_stats)
-                       card->perf_stats.outbound_time += qeth_get_micros() -
-                               card->perf_stats.outbound_start_time;
+               QETH_TXQ_STAT_INC(queue, tx_packets);
+               QETH_TXQ_STAT_ADD(queue, tx_bytes, tx_bytes);
                netif_wake_queue(dev);
                return NETDEV_TX_OK;
        } else if (rc == -EBUSY) {
@@ -2095,72 +2102,13 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
        } /* else fall through */
 
 tx_drop:
-       card->stats.tx_dropped++;
-       card->stats.tx_errors++;
+       QETH_TXQ_STAT_INC(queue, tx_dropped);
+       QETH_TXQ_STAT_INC(queue, tx_errors);
        dev_kfree_skb_any(skb);
        netif_wake_queue(dev);
        return NETDEV_TX_OK;
 }
 
-static int __qeth_l3_open(struct net_device *dev)
-{
-       struct qeth_card *card = dev->ml_priv;
-       int rc = 0;
-
-       QETH_CARD_TEXT(card, 4, "qethopen");
-       if (card->state == CARD_STATE_UP)
-               return rc;
-       if (card->state != CARD_STATE_SOFTSETUP)
-               return -ENODEV;
-       card->data.state = CH_STATE_UP;
-       card->state = CARD_STATE_UP;
-       netif_start_queue(dev);
-
-       if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
-               napi_enable(&card->napi);
-               local_bh_disable();
-               napi_schedule(&card->napi);
-               /* kick-start the NAPI softirq: */
-               local_bh_enable();
-       } else
-               rc = -EIO;
-       return rc;
-}
-
-static int qeth_l3_open(struct net_device *dev)
-{
-       struct qeth_card *card = dev->ml_priv;
-
-       QETH_CARD_TEXT(card, 5, "qethope_");
-       if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
-               QETH_CARD_TEXT(card, 3, "openREC");
-               return -ERESTARTSYS;
-       }
-       return __qeth_l3_open(dev);
-}
-
-static int qeth_l3_stop(struct net_device *dev)
-{
-       struct qeth_card *card = dev->ml_priv;
-
-       QETH_CARD_TEXT(card, 4, "qethstop");
-       netif_tx_disable(dev);
-       if (card->state == CARD_STATE_UP) {
-               card->state = CARD_STATE_SOFTSETUP;
-               napi_disable(&card->napi);
-       }
-       return 0;
-}
-
-static const struct ethtool_ops qeth_l3_ethtool_ops = {
-       .get_link = ethtool_op_get_link,
-       .get_strings = qeth_core_get_strings,
-       .get_ethtool_stats = qeth_core_get_ethtool_stats,
-       .get_sset_count = qeth_core_get_sset_count,
-       .get_drvinfo = qeth_core_get_drvinfo,
-       .get_link_ksettings = qeth_core_ethtool_get_link_ksettings,
-};
-
 /*
  * we need NOARP for IPv4 but we want neighbor solicitation for IPv6. Setting
  * NOARP on the netdevice is no option because it also turns off neighbor
@@ -2195,9 +2143,9 @@ static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb,
 }
 
 static const struct net_device_ops qeth_l3_netdev_ops = {
-       .ndo_open               = qeth_l3_open,
-       .ndo_stop               = qeth_l3_stop,
-       .ndo_get_stats          = qeth_get_stats,
+       .ndo_open               = qeth_open,
+       .ndo_stop               = qeth_stop,
+       .ndo_get_stats64        = qeth_get_stats64,
        .ndo_start_xmit         = qeth_l3_hard_start_xmit,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_rx_mode        = qeth_l3_set_rx_mode,
@@ -2210,9 +2158,9 @@ static const struct net_device_ops qeth_l3_netdev_ops = {
 };
 
 static const struct net_device_ops qeth_l3_osa_netdev_ops = {
-       .ndo_open               = qeth_l3_open,
-       .ndo_stop               = qeth_l3_stop,
-       .ndo_get_stats          = qeth_get_stats,
+       .ndo_open               = qeth_open,
+       .ndo_stop               = qeth_stop,
+       .ndo_get_stats64        = qeth_get_stats64,
        .ndo_start_xmit         = qeth_l3_hard_start_xmit,
        .ndo_features_check     = qeth_l3_osa_features_check,
        .ndo_validate_addr      = eth_validate_addr,
@@ -2231,9 +2179,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok)
        unsigned int headroom;
        int rc;
 
-       if (qeth_netdev_is_registered(card->dev))
-               return 0;
-
        if (card->info.type == QETH_CARD_TYPE_OSD ||
            card->info.type == QETH_CARD_TYPE_OSX) {
                if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
@@ -2285,7 +2230,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok)
                return -ENODEV;
 
        card->dev->needed_headroom = headroom;
-       card->dev->ethtool_ops = &qeth_l3_ethtool_ops;
        card->dev->features |=  NETIF_F_HW_VLAN_CTAG_TX |
                                NETIF_F_HW_VLAN_CTAG_RX |
                                NETIF_F_HW_VLAN_CTAG_FILTER;
@@ -2347,11 +2291,11 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
        qeth_l3_clear_ipato_list(card);
 }
 
-static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
+static int qeth_l3_set_online(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       struct net_device *dev = card->dev;
        int rc = 0;
-       enum qeth_card_states recover_flag;
        bool carrier_ok;
 
        mutex_lock(&card->discipline_mutex);
@@ -2359,7 +2303,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        QETH_DBF_TEXT(SETUP, 2, "setonlin");
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
 
-       recover_flag = card->state;
        rc = qeth_core_hardsetup_card(card, &carrier_ok);
        if (rc) {
                QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
@@ -2367,10 +2310,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                goto out_remove;
        }
 
-       rc = qeth_l3_setup_netdev(card, carrier_ok);
-       if (rc)
-               goto out_remove;
-
        if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
                if (card->info.hwtrap &&
                    qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM))
@@ -2400,7 +2339,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                if (rc)
                        QETH_DBF_TEXT_(SETUP, 2, "5err%04x", rc);
        }
-       netif_tx_disable(card->dev);
 
        rc = qeth_init_qdio_queues(card);
        if (rc) {
@@ -2413,14 +2351,23 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        qeth_set_allowed_threads(card, 0xffffffff, 0);
        qeth_l3_recover_ip(card);
 
-       qeth_enable_hw_features(card->dev);
-       if (recover_flag == CARD_STATE_RECOVER) {
+       if (!qeth_netdev_is_registered(dev)) {
+               rc = qeth_l3_setup_netdev(card, carrier_ok);
+               if (rc)
+                       goto out_remove;
+       } else {
                rtnl_lock();
-               if (recovery_mode) {
-                       __qeth_l3_open(card->dev);
-                       qeth_l3_set_rx_mode(card->dev);
-               } else {
-                       dev_open(card->dev, NULL);
+               if (carrier_ok)
+                       netif_carrier_on(dev);
+               else
+                       netif_carrier_off(dev);
+
+               netif_device_attach(dev);
+               qeth_enable_hw_features(dev);
+
+               if (card->info.open_when_online) {
+                       card->info.open_when_online = 0;
+                       dev_open(dev, NULL);
                }
                rtnl_unlock();
        }
@@ -2431,45 +2378,43 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        mutex_unlock(&card->discipline_mutex);
        return 0;
 out_remove:
-       qeth_l3_stop_card(card, 0);
+       qeth_l3_stop_card(card);
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
        qdio_free(CARD_DDEV(card));
-       if (recover_flag == CARD_STATE_RECOVER)
-               card->state = CARD_STATE_RECOVER;
-       else
-               card->state = CARD_STATE_DOWN;
+       card->state = CARD_STATE_DOWN;
+
        mutex_unlock(&card->conf_mutex);
        mutex_unlock(&card->discipline_mutex);
        return rc;
 }
 
-static int qeth_l3_set_online(struct ccwgroup_device *gdev)
-{
-       return __qeth_l3_set_online(gdev, 0);
-}
-
 static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
                        int recovery_mode)
 {
        struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
        int rc = 0, rc2 = 0, rc3 = 0;
-       enum qeth_card_states recover_flag;
 
        mutex_lock(&card->discipline_mutex);
        mutex_lock(&card->conf_mutex);
        QETH_DBF_TEXT(SETUP, 3, "setoffl");
        QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
 
-       netif_carrier_off(card->dev);
-       recover_flag = card->state;
        if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
                qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
                card->info.hwtrap = 1;
        }
-       qeth_l3_stop_card(card, recovery_mode);
-       if ((card->options.cq == QETH_CQ_ENABLED) && card->dev) {
+
+       rtnl_lock();
+       card->info.open_when_online = card->dev->flags & IFF_UP;
+       dev_close(card->dev);
+       netif_device_detach(card->dev);
+       netif_carrier_off(card->dev);
+       rtnl_unlock();
+
+       qeth_l3_stop_card(card);
+       if (card->options.cq == QETH_CQ_ENABLED) {
                rtnl_lock();
                call_netdevice_notifiers(NETDEV_REBOOT, card->dev);
                rtnl_unlock();
@@ -2482,8 +2427,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
        if (rc)
                QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
        qdio_free(CARD_DDEV(card));
-       if (recover_flag == CARD_STATE_UP)
-               card->state = CARD_STATE_RECOVER;
+
        /* let user_space know that device is offline */
        kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE);
        mutex_unlock(&card->conf_mutex);
@@ -2509,9 +2453,8 @@ static int qeth_l3_recover(void *ptr)
        QETH_CARD_TEXT(card, 2, "recover2");
        dev_warn(&card->gdev->dev,
                "A recovery process has been started for the device\n");
-       qeth_set_recovery_task(card);
        __qeth_l3_set_offline(card->gdev, 1);
-       rc = __qeth_l3_set_online(card->gdev, 1);
+       rc = qeth_l3_set_online(card->gdev);
        if (!rc)
                dev_info(&card->gdev->dev,
                        "Device successfully recovered!\n");
@@ -2520,7 +2463,6 @@ static int qeth_l3_recover(void *ptr)
                dev_warn(&card->gdev->dev, "The qeth device driver "
                                "failed to recover an error on the device\n");
        }
-       qeth_clear_recovery_task(card);
        qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
        qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
        return 0;
@@ -2530,7 +2472,6 @@ static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card = dev_get_drvdata(&gdev->dev);
 
-       netif_device_detach(card->dev);
        qeth_set_allowed_threads(card, 0, 1);
        wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
        if (gdev->state == CCWGROUP_OFFLINE)
@@ -2547,20 +2488,11 @@ static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
 static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card = dev_get_drvdata(&gdev->dev);
-       int rc = 0;
+       int rc;
 
-       if (card->state == CARD_STATE_RECOVER) {
-               rc = __qeth_l3_set_online(card->gdev, 1);
-               if (rc) {
-                       rtnl_lock();
-                       dev_close(card->dev);
-                       rtnl_unlock();
-               }
-       } else
-               rc = __qeth_l3_set_online(card->gdev, 0);
+       rc = qeth_l3_set_online(gdev);
 
        qeth_set_allowed_threads(card, 0xffffffff, 0);
-       netif_device_attach(card->dev);
        if (rc)
                dev_warn(&card->gdev->dev, "The qeth device driver "
                        "failed to recover an error on the device\n");