QETH_CARD_TEXT(card, 6, "noirqpnd");
        rc = ccw_device_start(channel->ccwdev, ccw, (addr_t) iob, 0, 0);
-       if (rc) {
+       if (!rc) {
+               channel->active_cmd = iob;
+       } else {
                QETH_DBF_MESSAGE(2, "error %i on device %x when starting next read ccw!\n",
                                 rc, CARD_DEVID(card));
                atomic_set(&channel->irq_pending, 0);
                QETH_CARD_TEXT(card, 5, "data");
        }
 
-       if (qeth_intparm_is_iob(intparm))
-               iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
+       if (intparm == 0) {
+               QETH_CARD_TEXT(card, 5, "irqunsol");
+       } else if ((addr_t)intparm != (addr_t)channel->active_cmd) {
+               QETH_CARD_TEXT(card, 5, "irqunexp");
+
+               dev_err(&cdev->dev,
+                       "Received IRQ with intparm %lx, expected %px\n",
+                       intparm, channel->active_cmd);
+               if (channel->active_cmd)
+                       qeth_cancel_cmd(channel->active_cmd, -EIO);
+       } else {
+               iob = (struct qeth_cmd_buffer *) (addr_t)intparm;
+       }
+
+       channel->active_cmd = NULL;
 
        rc = qeth_check_irb_error(card, cdev, irb);
        if (rc) {
        if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC))
                channel->state = CH_STATE_HALTED;
 
-       if (intparm == QETH_CLEAR_CHANNEL_PARM) {
-               QETH_CARD_TEXT(card, 6, "clrchpar");
-               /* we don't have to handle this further */
-               intparm = 0;
-       }
-       if (intparm == QETH_HALT_CHANNEL_PARM) {
-               QETH_CARD_TEXT(card, 6, "hltchpar");
-               /* we don't have to handle this further */
-               intparm = 0;
+       if (iob && (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC |
+                                         SCSW_FCTL_HALT_FUNC))) {
+               qeth_cancel_cmd(iob, -ECANCELED);
+               iob = NULL;
        }
 
        cstat = irb->scsw.cmd.cstat;
 
        QETH_CARD_TEXT(card, 3, "clearch");
        spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
-       rc = ccw_device_clear(channel->ccwdev, QETH_CLEAR_CHANNEL_PARM);
+       rc = ccw_device_clear(channel->ccwdev, (addr_t)channel->active_cmd);
        spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
 
        if (rc)
 
        QETH_CARD_TEXT(card, 3, "haltch");
        spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
-       rc = ccw_device_halt(channel->ccwdev, QETH_HALT_CHANNEL_PARM);
+       rc = ccw_device_halt(channel->ccwdev, (addr_t)channel->active_cmd);
        spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
 
        if (rc)
        return 0;
 }
 
+int qeth_stop_channel(struct qeth_channel *channel)
+{
+       struct ccw_device *cdev = channel->ccwdev;
+       int rc;
+
+       rc = ccw_device_set_offline(cdev);
+
+       spin_lock_irq(get_ccwdev_lock(cdev));
+       if (channel->active_cmd) {
+               dev_err(&cdev->dev, "Stopped channel while cmd %px was still active\n",
+                       channel->active_cmd);
+               channel->active_cmd = NULL;
+       }
+       spin_unlock_irq(get_ccwdev_lock(cdev));
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(qeth_stop_channel);
+
 static int qeth_halt_channels(struct qeth_card *card)
 {
        int rc1 = 0, rc2 = 0, rc3 = 0;
        spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
        rc = ccw_device_start_timeout(channel->ccwdev, __ccw_from_cmd(iob),
                                      (addr_t) iob, 0, 0, timeout);
+       if (!rc)
+               channel->active_cmd = iob;
        spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
        if (rc) {
                QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n",
 
 static void qeth_determine_capabilities(struct qeth_card *card)
 {
+       struct qeth_channel *channel = &card->data;
+       struct ccw_device *ddev = channel->ccwdev;
        int rc;
-       struct ccw_device *ddev;
        int ddev_offline = 0;
 
        QETH_CARD_TEXT(card, 2, "detcapab");
-       ddev = CARD_DDEV(card);
        if (!ddev->online) {
                ddev_offline = 1;
                rc = ccw_device_set_online(ddev);
 
 out_offline:
        if (ddev_offline == 1)
-               ccw_device_set_offline(ddev);
+               qeth_stop_channel(channel);
 out:
        return;
 }
                QETH_DBF_MESSAGE(2, "Retrying to do IDX activates on device %x.\n",
                                 CARD_DEVID(card));
        rc = qeth_qdio_clear_card(card, !IS_IQD(card));
-       ccw_device_set_offline(CARD_DDEV(card));
-       ccw_device_set_offline(CARD_WDEV(card));
-       ccw_device_set_offline(CARD_RDEV(card));
+       qeth_stop_channel(&card->data);
+       qeth_stop_channel(&card->write);
+       qeth_stop_channel(&card->read);
        qdio_free(CARD_DDEV(card));
        rc = ccw_device_set_online(CARD_RDEV(card));
        if (rc)