}
 }
 
+/**
+ * qeth_irq() - qeth interrupt handler
+ * @cdev: ccw device
+ * @intparm: expect pointer to iob
+ * @irb: Interruption Response Block
+ *
+ * In the good path:
+ * corresponding qeth channel is locked with last used iob as active_cmd.
+ * But this function is also called for error interrupts.
+ *
+ * Caller ensures that:
+ * Interrupts are disabled; ccw device lock is held;
+ *
+ */
 static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
                struct irb *irb)
 {
                iob = (struct qeth_cmd_buffer *) (addr_t)intparm;
        }
 
-       qeth_unlock_channel(card, channel);
-
        rc = qeth_check_irb_error(card, cdev, irb);
        if (rc) {
                /* IO was terminated, free its resources. */
+               qeth_unlock_channel(card, channel);
                if (iob)
                        qeth_cancel_cmd(iob, rc);
                return;
                rc = qeth_get_problem(card, cdev, irb);
                if (rc) {
                        card->read_or_write_problem = 1;
+                       qeth_unlock_channel(card, channel);
                        if (iob)
                                qeth_cancel_cmd(iob, rc);
                        qeth_clear_ipacmd_list(card);
                }
        }
 
+       if (scsw_cmd_is_valid_cc(&irb->scsw) && irb->scsw.cmd.cc == 1 && iob) {
+               /* channel command hasn't started: retry.
+                * active_cmd is still set to last iob
+                */
+               QETH_CARD_TEXT(card, 2, "irqcc1");
+               rc = ccw_device_start_timeout(cdev, __ccw_from_cmd(iob),
+                                             (addr_t)iob, 0, 0, iob->timeout);
+               if (rc) {
+                       QETH_DBF_MESSAGE(2,
+                                        "ccw retry on %x failed, rc = %i\n",
+                                        CARD_DEVID(card), rc);
+                       QETH_CARD_TEXT_(card, 2, " err%d", rc);
+                       qeth_unlock_channel(card, channel);
+                       qeth_cancel_cmd(iob, rc);
+               }
+               return;
+       }
+
+       qeth_unlock_channel(card, channel);
+
        if (iob) {
                /* sanity check: */
                if (irb->scsw.cmd.count > iob->length) {