static void qeth_qdio_handle_aob(struct qeth_card *card,
                                 unsigned long phys_aob_addr)
 {
+       enum qeth_qdio_out_buffer_state new_state = QETH_QDIO_BUF_QAOB_OK;
        struct qaob *aob;
        struct qeth_qdio_out_buffer *buffer;
        enum iucv_tx_notify notification;
        buffer = (struct qeth_qdio_out_buffer *) aob->user1;
        QETH_CARD_TEXT_(card, 5, "%lx", aob->user1);
 
-       if (atomic_cmpxchg(&buffer->state, QETH_QDIO_BUF_PRIMED,
-                          QETH_QDIO_BUF_IN_CQ) == QETH_QDIO_BUF_PRIMED) {
-               notification = TX_NOTIFY_OK;
-       } else {
-               WARN_ON_ONCE(atomic_read(&buffer->state) !=
-                                                       QETH_QDIO_BUF_PENDING);
-               atomic_set(&buffer->state, QETH_QDIO_BUF_IN_CQ);
-               notification = TX_NOTIFY_DELAYED_OK;
-       }
-
-       if (aob->aorc != 0)  {
-               QETH_CARD_TEXT_(card, 2, "aorc%02X", aob->aorc);
-               notification = qeth_compute_cq_notification(aob->aorc, 1);
-       }
-       qeth_notify_skbs(buffer->q, buffer, notification);
-
        /* Free dangling allocations. The attached skbs are handled by
         * qeth_cleanup_handled_pending().
         */
                if (data && buffer->is_header[i])
                        kmem_cache_free(qeth_core_header_cache, data);
        }
-       atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED);
+
+       if (aob->aorc) {
+               QETH_CARD_TEXT_(card, 2, "aorc%02X", aob->aorc);
+               new_state = QETH_QDIO_BUF_QAOB_ERROR;
+       }
+
+       switch (atomic_xchg(&buffer->state, new_state)) {
+       case QETH_QDIO_BUF_PRIMED:
+               /* Faster than TX completion code. */
+               notification = qeth_compute_cq_notification(aob->aorc, 0);
+               qeth_notify_skbs(buffer->q, buffer, notification);
+               atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED);
+               break;
+       case QETH_QDIO_BUF_PENDING:
+               /* TX completion code is active and will handle the async
+                * completion for us.
+                */
+               break;
+       case QETH_QDIO_BUF_NEED_QAOB:
+               /* TX completion code is already finished. */
+               notification = qeth_compute_cq_notification(aob->aorc, 1);
+               qeth_notify_skbs(buffer->q, buffer, notification);
+               atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+       }
 
        qdio_release_aob(aob);
 }
        struct qeth_qdio_out_q *queue = buf->q;
        struct sk_buff *skb;
 
-       /* release may never happen from within CQ tasklet scope */
-       WARN_ON_ONCE(atomic_read(&buf->state) == QETH_QDIO_BUF_IN_CQ);
-
        if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING)
                qeth_notify_skbs(queue, buf, TX_NOTIFY_GENERALERROR);
 
 
                if (atomic_cmpxchg(&buffer->state, QETH_QDIO_BUF_PRIMED,
                                                   QETH_QDIO_BUF_PENDING) ==
-                   QETH_QDIO_BUF_PRIMED)
+                   QETH_QDIO_BUF_PRIMED) {
                        qeth_notify_skbs(queue, buffer, TX_NOTIFY_PENDING);
 
+                       /* Handle race with qeth_qdio_handle_aob(): */
+                       switch (atomic_xchg(&buffer->state,
+                                           QETH_QDIO_BUF_NEED_QAOB)) {
+                       case QETH_QDIO_BUF_PENDING:
+                               /* No concurrent QAOB notification. */
+                               break;
+                       case QETH_QDIO_BUF_QAOB_OK:
+                               qeth_notify_skbs(queue, buffer,
+                                                TX_NOTIFY_DELAYED_OK);
+                               atomic_set(&buffer->state,
+                                          QETH_QDIO_BUF_HANDLED_DELAYED);
+                               break;
+                       case QETH_QDIO_BUF_QAOB_ERROR:
+                               qeth_notify_skbs(queue, buffer,
+                                                TX_NOTIFY_DELAYED_GENERALERROR);
+                               atomic_set(&buffer->state,
+                                          QETH_QDIO_BUF_HANDLED_DELAYED);
+                               break;
+                       default:
+                               WARN_ON_ONCE(1);
+                       }
+               }
+
                QETH_CARD_TEXT_(card, 5, "pel%u", bidx);
 
                /* prepare the queue slot for re-use: */