]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 's390-qeth-fixes'
authorDavid S. Miller <davem@davemloft.net>
Sun, 22 Apr 2018 18:42:32 +0000 (14:42 -0400)
committerDavid S. Miller <davem@davemloft.net>
Sun, 22 Apr 2018 18:42:32 +0000 (14:42 -0400)
Julian Wiedmann says:

====================
s390/qeth: fixes 2018-04-19

Please apply the following qeth fixes for 4.17. The common theme
seems to be error handling improvements in various areas of cmd IO.

Patches 1-3 should also go back to stable.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_core_mpc.h
drivers/s390/net/qeth_l2_main.c

index 4326715dc13eb18af4c69cc233f279ab264fae36..78b98b3e7efaf3893d0451ca6524220c94a26994 100644 (file)
@@ -557,7 +557,6 @@ enum qeth_prot_versions {
 enum qeth_cmd_buffer_state {
        BUF_STATE_FREE,
        BUF_STATE_LOCKED,
-       BUF_STATE_PROCESSED,
 };
 
 enum qeth_cq {
@@ -601,7 +600,6 @@ struct qeth_channel {
        struct qeth_cmd_buffer iob[QETH_CMD_BUFFER_NO];
        atomic_t irq_pending;
        int io_buf_no;
-       int buf_no;
 };
 
 /**
index 04fefa5bb08d168b7beefeeef62b1190aab84232..dffd820731f2a53f9a5c58f0f9da78df72c2a0cf 100644 (file)
@@ -706,7 +706,6 @@ void qeth_clear_ipacmd_list(struct qeth_card *card)
                qeth_put_reply(reply);
        }
        spin_unlock_irqrestore(&card->lock, flags);
-       atomic_set(&card->write.irq_pending, 0);
 }
 EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
 
@@ -818,7 +817,6 @@ void qeth_clear_cmd_buffers(struct qeth_channel *channel)
 
        for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++)
                qeth_release_buffer(channel, &channel->iob[cnt]);
-       channel->buf_no = 0;
        channel->io_buf_no = 0;
 }
 EXPORT_SYMBOL_GPL(qeth_clear_cmd_buffers);
@@ -924,7 +922,6 @@ static int qeth_setup_channel(struct qeth_channel *channel)
                        kfree(channel->iob[cnt].data);
                return -ENOMEM;
        }
-       channel->buf_no = 0;
        channel->io_buf_no = 0;
        atomic_set(&channel->irq_pending, 0);
        spin_lock_init(&channel->iob_lock);
@@ -1100,16 +1097,9 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
 {
        int rc;
        int cstat, dstat;
-       struct qeth_cmd_buffer *buffer;
+       struct qeth_cmd_buffer *iob = NULL;
        struct qeth_channel *channel;
        struct qeth_card *card;
-       struct qeth_cmd_buffer *iob;
-       __u8 index;
-
-       if (__qeth_check_irb_error(cdev, intparm, irb))
-               return;
-       cstat = irb->scsw.cmd.cstat;
-       dstat = irb->scsw.cmd.dstat;
 
        card = CARD_FROM_CDEV(cdev);
        if (!card)
@@ -1127,6 +1117,19 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
                channel = &card->data;
                QETH_CARD_TEXT(card, 5, "data");
        }
+
+       if (qeth_intparm_is_iob(intparm))
+               iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
+
+       if (__qeth_check_irb_error(cdev, intparm, irb)) {
+               /* IO was terminated, free its resources. */
+               if (iob)
+                       qeth_release_buffer(iob->channel, iob);
+               atomic_set(&channel->irq_pending, 0);
+               wake_up(&card->wait_q);
+               return;
+       }
+
        atomic_set(&channel->irq_pending, 0);
 
        if (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC))
@@ -1150,6 +1153,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
                /* we don't have to handle this further */
                intparm = 0;
        }
+
+       cstat = irb->scsw.cmd.cstat;
+       dstat = irb->scsw.cmd.dstat;
+
        if ((dstat & DEV_STAT_UNIT_EXCEP) ||
            (dstat & DEV_STAT_UNIT_CHECK) ||
            (cstat)) {
@@ -1182,25 +1189,15 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
                channel->state = CH_STATE_RCD_DONE;
                goto out;
        }
-       if (intparm) {
-               buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
-               buffer->state = BUF_STATE_PROCESSED;
-       }
        if (channel == &card->data)
                return;
        if (channel == &card->read &&
            channel->state == CH_STATE_UP)
                __qeth_issue_next_read(card);
 
-       iob = channel->iob;
-       index = channel->buf_no;
-       while (iob[index].state == BUF_STATE_PROCESSED) {
-               if (iob[index].callback != NULL)
-                       iob[index].callback(channel, iob + index);
+       if (iob && iob->callback)
+               iob->callback(iob->channel, iob);
 
-               index = (index + 1) % QETH_CMD_BUFFER_NO;
-       }
-       channel->buf_no = index;
 out:
        wake_up(&card->wait_q);
        return;
@@ -1870,8 +1867,8 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
                   atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
        QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
        spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
-       rc = ccw_device_start(channel->ccwdev,
-                             &channel->ccw, (addr_t) iob, 0, 0);
+       rc = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
+                                     (addr_t) iob, 0, 0, QETH_TIMEOUT);
        spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
 
        if (rc) {
@@ -1888,7 +1885,6 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
        if (channel->state != CH_STATE_UP) {
                rc = -ETIME;
                QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
-               qeth_clear_cmd_buffers(channel);
        } else
                rc = 0;
        return rc;
@@ -1942,8 +1938,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
                   atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
        QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
        spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
-       rc = ccw_device_start(channel->ccwdev,
-                             &channel->ccw, (addr_t) iob, 0, 0);
+       rc = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
+                                     (addr_t) iob, 0, 0, QETH_TIMEOUT);
        spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
 
        if (rc) {
@@ -1964,7 +1960,6 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
                QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n",
                        dev_name(&channel->ccwdev->dev));
                QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME);
-               qeth_clear_cmd_buffers(channel);
                return -ETIME;
        }
        return qeth_idx_activate_get_answer(channel, idx_reply_cb);
@@ -2166,8 +2161,8 @@ int qeth_send_control_data(struct qeth_card *card, int len,
 
        QETH_CARD_TEXT(card, 6, "noirqpnd");
        spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
-       rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
-                             (addr_t) iob, 0, 0);
+       rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
+                                     (addr_t) iob, 0, 0, event_timeout);
        spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
        if (rc) {
                QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: "
@@ -2199,8 +2194,6 @@ int qeth_send_control_data(struct qeth_card *card, int len,
                }
        }
 
-       if (reply->rc == -EIO)
-               goto error;
        rc = reply->rc;
        qeth_put_reply(reply);
        return rc;
@@ -2211,10 +2204,6 @@ int qeth_send_control_data(struct qeth_card *card, int len,
        list_del_init(&reply->list);
        spin_unlock_irqrestore(&reply->card->lock, flags);
        atomic_inc(&reply->received);
-error:
-       atomic_set(&card->write.irq_pending, 0);
-       qeth_release_buffer(iob->channel, iob);
-       card->write.buf_no = (card->write.buf_no + 1) % QETH_CMD_BUFFER_NO;
        rc = reply->rc;
        qeth_put_reply(reply);
        return rc;
@@ -3033,28 +3022,23 @@ static int qeth_send_startlan(struct qeth_card *card)
        return rc;
 }
 
-static int qeth_default_setadapterparms_cb(struct qeth_card *card,
-               struct qeth_reply *reply, unsigned long data)
+static int qeth_setadpparms_inspect_rc(struct qeth_ipa_cmd *cmd)
 {
-       struct qeth_ipa_cmd *cmd;
-
-       QETH_CARD_TEXT(card, 4, "defadpcb");
-
-       cmd = (struct qeth_ipa_cmd *) data;
-       if (cmd->hdr.return_code == 0)
+       if (!cmd->hdr.return_code)
                cmd->hdr.return_code =
                        cmd->data.setadapterparms.hdr.return_code;
-       return 0;
+       return cmd->hdr.return_code;
 }
 
 static int qeth_query_setadapterparms_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;
 
        QETH_CARD_TEXT(card, 3, "quyadpcb");
+       if (qeth_setadpparms_inspect_rc(cmd))
+               return 0;
 
-       cmd = (struct qeth_ipa_cmd *) data;
        if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) {
                card->info.link_type =
                      cmd->data.setadapterparms.data.query_cmds_supp.lan_type;
@@ -3062,7 +3046,7 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card,
        }
        card->options.adp.supported_funcs =
                cmd->data.setadapterparms.data.query_cmds_supp.supported_cmds;
-       return qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
+       return 0;
 }
 
 static struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,
@@ -3154,22 +3138,20 @@ EXPORT_SYMBOL_GPL(qeth_query_ipassists);
 static int qeth_query_switch_attributes_cb(struct qeth_card *card,
                                struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
-       struct qeth_switch_info *sw_info;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
        struct qeth_query_switch_attributes *attrs;
+       struct qeth_switch_info *sw_info;
 
        QETH_CARD_TEXT(card, 2, "qswiatcb");
-       cmd = (struct qeth_ipa_cmd *) data;
-       sw_info = (struct qeth_switch_info *)reply->param;
-       if (cmd->data.setadapterparms.hdr.return_code == 0) {
-               attrs = &cmd->data.setadapterparms.data.query_switch_attributes;
-               sw_info->capabilities = attrs->capabilities;
-               sw_info->settings = attrs->settings;
-               QETH_CARD_TEXT_(card, 2, "%04x%04x", sw_info->capabilities,
-                                                       sw_info->settings);
-       }
-       qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
+       if (qeth_setadpparms_inspect_rc(cmd))
+               return 0;
 
+       sw_info = (struct qeth_switch_info *)reply->param;
+       attrs = &cmd->data.setadapterparms.data.query_switch_attributes;
+       sw_info->capabilities = attrs->capabilities;
+       sw_info->settings = attrs->settings;
+       QETH_CARD_TEXT_(card, 2, "%04x%04x", sw_info->capabilities,
+                       sw_info->settings);
        return 0;
 }
 
@@ -4207,16 +4189,13 @@ EXPORT_SYMBOL_GPL(qeth_do_send_packet);
 static int qeth_setadp_promisc_mode_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;
        struct qeth_ipacmd_setadpparms *setparms;
 
        QETH_CARD_TEXT(card, 4, "prmadpcb");
 
-       cmd = (struct qeth_ipa_cmd *) data;
        setparms = &(cmd->data.setadapterparms);
-
-       qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
-       if (cmd->hdr.return_code) {
+       if (qeth_setadpparms_inspect_rc(cmd)) {
                QETH_CARD_TEXT_(card, 4, "prmrc%x", cmd->hdr.return_code);
                setparms->data.mode = SET_PROMISC_MODE_OFF;
        }
@@ -4286,18 +4265,18 @@ EXPORT_SYMBOL_GPL(qeth_get_stats);
 static int qeth_setadpparms_change_macaddr_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;
 
        QETH_CARD_TEXT(card, 4, "chgmaccb");
+       if (qeth_setadpparms_inspect_rc(cmd))
+               return 0;
 
-       cmd = (struct qeth_ipa_cmd *) data;
        if (!card->options.layer2 ||
            !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
                ether_addr_copy(card->dev->dev_addr,
                                cmd->data.setadapterparms.data.change_addr.addr);
                card->info.mac_bits |= QETH_LAYER2_MAC_READ;
        }
-       qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
        return 0;
 }
 
@@ -4328,13 +4307,15 @@ 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_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
        struct qeth_set_access_ctrl *access_ctrl_req;
        int fallback = *(int *)reply->param;
 
        QETH_CARD_TEXT(card, 4, "setaccb");
+       if (cmd->hdr.return_code)
+               return 0;
+       qeth_setadpparms_inspect_rc(cmd);
 
-       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);
@@ -4407,7 +4388,6 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
                        card->options.isolation = card->options.prev_isolation;
                break;
        }
-       qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
        return 0;
 }
 
@@ -4695,14 +4675,15 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
 static int qeth_setadpparms_query_oat_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;
        struct qeth_qoat_priv *priv;
        char *resdata;
        int resdatalen;
 
        QETH_CARD_TEXT(card, 3, "qoatcb");
+       if (qeth_setadpparms_inspect_rc(cmd))
+               return 0;
 
-       cmd = (struct qeth_ipa_cmd *)data;
        priv = (struct qeth_qoat_priv *)reply->param;
        resdatalen = cmd->data.setadapterparms.hdr.cmdlength;
        resdata = (char *)data + 28;
@@ -4796,21 +4777,18 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata)
 static int qeth_query_card_info_cb(struct qeth_card *card,
                                   struct qeth_reply *reply, unsigned long data)
 {
-       struct qeth_ipa_cmd *cmd;
+       struct carrier_info *carrier_info = (struct carrier_info *)reply->param;
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data;
        struct qeth_query_card_info *card_info;
-       struct carrier_info *carrier_info;
 
        QETH_CARD_TEXT(card, 2, "qcrdincb");
-       carrier_info = (struct carrier_info *)reply->param;
-       cmd = (struct qeth_ipa_cmd *)data;
-       card_info = &cmd->data.setadapterparms.data.card_info;
-       if (cmd->data.setadapterparms.hdr.return_code == 0) {
-               carrier_info->card_type = card_info->card_type;
-               carrier_info->port_mode = card_info->port_mode;
-               carrier_info->port_speed = card_info->port_speed;
-       }
+       if (qeth_setadpparms_inspect_rc(cmd))
+               return 0;
 
-       qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
+       card_info = &cmd->data.setadapterparms.data.card_info;
+       carrier_info->card_type = card_info->card_type;
+       carrier_info->port_mode = card_info->port_mode;
+       carrier_info->port_speed = card_info->port_speed;
        return 0;
 }
 
@@ -4857,7 +4835,7 @@ int qeth_vm_request_mac(struct qeth_card *card)
                goto out;
        }
 
-       ccw_device_get_id(CARD_DDEV(card), &id);
+       ccw_device_get_id(CARD_RDEV(card), &id);
        request->resp_buf_len = sizeof(*response);
        request->resp_version = DIAG26C_VERSION2;
        request->op_code = DIAG26C_GET_MAC;
@@ -6563,10 +6541,14 @@ static int __init qeth_core_init(void)
        mutex_init(&qeth_mod_mutex);
 
        qeth_wq = create_singlethread_workqueue("qeth_wq");
+       if (!qeth_wq) {
+               rc = -ENOMEM;
+               goto out_err;
+       }
 
        rc = qeth_register_dbf_views();
        if (rc)
-               goto out_err;
+               goto dbf_err;
        qeth_core_root_dev = root_device_register("qeth");
        rc = PTR_ERR_OR_ZERO(qeth_core_root_dev);
        if (rc)
@@ -6603,6 +6585,8 @@ static int __init qeth_core_init(void)
        root_device_unregister(qeth_core_root_dev);
 register_err:
        qeth_unregister_dbf_views();
+dbf_err:
+       destroy_workqueue(qeth_wq);
 out_err:
        pr_err("Initializing the qeth device driver failed\n");
        return rc;
index 619f897b4bb0cef7be641f6e45c8f31a1502409c..f4d1ec0b8f5a2018a6fbfaf61bd2a19792aa9aac 100644 (file)
@@ -35,6 +35,18 @@ extern unsigned char IPA_PDU_HEADER[];
 #define QETH_HALT_CHANNEL_PARM -11
 #define QETH_RCD_PARM -12
 
+static inline bool qeth_intparm_is_iob(unsigned long intparm)
+{
+       switch (intparm) {
+       case QETH_CLEAR_CHANNEL_PARM:
+       case QETH_HALT_CHANNEL_PARM:
+       case QETH_RCD_PARM:
+       case 0:
+               return false;
+       }
+       return true;
+}
+
 /*****************************************************************************/
 /* IP Assist related definitions                                             */
 /*****************************************************************************/
index 2ad6f12f3d497592484e2321fb02c39c7ca86962..b8079f2a65b3c636f0e1932437db72add1826df5 100644 (file)
@@ -121,13 +121,10 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
        QETH_CARD_TEXT(card, 2, "L2Setmac");
        rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC);
        if (rc == 0) {
-               card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
-               ether_addr_copy(card->dev->dev_addr, mac);
                dev_info(&card->gdev->dev,
-                       "MAC address %pM successfully registered on device %s\n",
-                       card->dev->dev_addr, card->dev->name);
+                        "MAC address %pM successfully registered on device %s\n",
+                        mac, card->dev->name);
        } else {
-               card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
                switch (rc) {
                case -EEXIST:
                        dev_warn(&card->gdev->dev,
@@ -142,19 +139,6 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
        return rc;
 }
 
-static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac)
-{
-       int rc;
-
-       QETH_CARD_TEXT(card, 2, "L2Delmac");
-       if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
-               return 0;
-       rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELVMAC);
-       if (rc == 0)
-               card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
-       return rc;
-}
-
 static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac)
 {
        enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ?
@@ -519,6 +503,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
 {
        struct sockaddr *addr = p;
        struct qeth_card *card = dev->ml_priv;
+       u8 old_addr[ETH_ALEN];
        int rc = 0;
 
        QETH_CARD_TEXT(card, 3, "setmac");
@@ -530,14 +515,35 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
                return -EOPNOTSUPP;
        }
        QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN);
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
        if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
                QETH_CARD_TEXT(card, 3, "setmcREC");
                return -ERESTARTSYS;
        }
-       rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]);
-       if (!rc || (rc == -ENOENT))
-               rc = qeth_l2_send_setmac(card, addr->sa_data);
-       return rc ? -EINVAL : 0;
+
+       if (!qeth_card_hw_is_reachable(card)) {
+               ether_addr_copy(dev->dev_addr, addr->sa_data);
+               return 0;
+       }
+
+       /* don't register the same address twice */
+       if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) &&
+           (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
+               return 0;
+
+       /* add the new address, switch over, drop the old */
+       rc = qeth_l2_send_setmac(card, addr->sa_data);
+       if (rc)
+               return rc;
+       ether_addr_copy(old_addr, dev->dev_addr);
+       ether_addr_copy(dev->dev_addr, addr->sa_data);
+
+       if (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED)
+               qeth_l2_remove_mac(card, old_addr);
+       card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
+       return 0;
 }
 
 static void qeth_promisc_to_bridge(struct qeth_card *card)
@@ -1067,8 +1073,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                goto out_remove;
        }
 
-       if (card->info.type != QETH_CARD_TYPE_OSN)
-               qeth_l2_send_setmac(card, &card->dev->dev_addr[0]);
+       if (card->info.type != QETH_CARD_TYPE_OSN &&
+           !qeth_l2_send_setmac(card, card->dev->dev_addr))
+               card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
 
        if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
                if (card->info.hwtrap &&
@@ -1338,8 +1345,8 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
        qeth_prepare_control_data(card, len, iob);
        QETH_CARD_TEXT(card, 6, "osnoirqp");
        spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
-       rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
-                             (addr_t) iob, 0, 0);
+       rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
+                                     (addr_t) iob, 0, 0, QETH_IPA_TIMEOUT);
        spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
        if (rc) {
                QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "