]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/s390/cio/qdio_main.c
[S390] qdio: report SIGA errors directly
[linux-2.6-omap-h63xx.git] / drivers / s390 / cio / qdio_main.c
index 31b9318149bac951ae2e1aa25f295a24a1b4e876..e53ac67e1e48fab708ccd849f166b014b1dfa9d9 100644 (file)
@@ -706,13 +706,13 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
                return 0;
 }
 
-static void qdio_kick_outbound_q(struct qdio_q *q)
+static int qdio_kick_outbound_q(struct qdio_q *q)
 {
        unsigned int busy_bit;
        int cc;
 
        if (!need_siga_out(q))
-               return;
+               return 0;
 
        DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
        qdio_perf_stat_inc(&perf_stats.siga_out);
@@ -724,19 +724,16 @@ static void qdio_kick_outbound_q(struct qdio_q *q)
        case 2:
                if (busy_bit) {
                        DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
-                       q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY;
-               } else {
-                       DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d",
-                                     q->nr);
-                       q->qdio_error = cc;
-               }
+                       cc |= QDIO_ERROR_SIGA_BUSY;
+               } else
+                       DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
                break;
        case 1:
        case 3:
                DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
-               q->qdio_error = cc;
                break;
        }
+       return cc;
 }
 
 static void qdio_kick_outbound_handler(struct qdio_q *q)
@@ -766,18 +763,12 @@ static void qdio_kick_outbound_handler(struct qdio_q *q)
 
 static void __qdio_outbound_processing(struct qdio_q *q)
 {
-       unsigned long flags;
-
        qdio_perf_stat_inc(&perf_stats.tasklet_outbound);
-       spin_lock_irqsave(&q->lock, flags);
-
        BUG_ON(atomic_read(&q->nr_buf_used) < 0);
 
        if (qdio_outbound_q_moved(q))
                qdio_kick_outbound_handler(q);
 
-       spin_unlock_irqrestore(&q->lock, flags);
-
        if (queue_type(q) == QDIO_ZFCP_QFMT)
                if (!pci_out_supported(q) && !qdio_outbound_q_done(q))
                        goto sched;
@@ -1457,10 +1448,10 @@ static inline int buf_in_between(int bufnr, int start, int count)
  * @bufnr: first buffer to process
  * @count: how many buffers are emptied
  */
-static void handle_inbound(struct qdio_q *q, unsigned int callflags,
-                          int bufnr, int count)
+static int handle_inbound(struct qdio_q *q, unsigned int callflags,
+                         int bufnr, int count)
 {
-       int used, cc, diff;
+       int used, diff;
 
        if (!q->u.in.polling)
                goto set;
@@ -1497,13 +1488,11 @@ set:
 
        /* no need to signal as long as the adapter had free buffers */
        if (used)
-               return;
+               return 0;
 
-       if (need_siga_in(q)) {
-               cc = qdio_siga_input(q);
-               if (cc)
-                       q->qdio_error = cc;
-       }
+       if (need_siga_in(q))
+               return qdio_siga_input(q);
+       return 0;
 }
 
 /**
@@ -1513,11 +1502,11 @@ set:
  * @bufnr: first buffer to process
  * @count: how many buffers are filled
  */
-static void handle_outbound(struct qdio_q *q, unsigned int callflags,
-                           int bufnr, int count)
+static int handle_outbound(struct qdio_q *q, unsigned int callflags,
+                          int bufnr, int count)
 {
        unsigned char state;
-       int used;
+       int used, rc = 0;
 
        qdio_perf_stat_inc(&perf_stats.outbound_handler);
 
@@ -1532,27 +1521,26 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
 
        if (queue_type(q) == QDIO_IQDIO_QFMT) {
                if (multicast_outbound(q))
-                       qdio_kick_outbound_q(q);
+                       rc = qdio_kick_outbound_q(q);
                else
                        if ((q->irq_ptr->ssqd_desc.mmwc > 1) &&
                            (count > 1) &&
                            (count <= q->irq_ptr->ssqd_desc.mmwc)) {
                                /* exploit enhanced SIGA */
                                q->u.out.use_enh_siga = 1;
-                               qdio_kick_outbound_q(q);
+                               rc = qdio_kick_outbound_q(q);
                        } else {
                                /*
                                * One siga-w per buffer required for unicast
                                * HiperSockets.
                                */
                                q->u.out.use_enh_siga = 0;
-                               while (count--)
-                                       qdio_kick_outbound_q(q);
+                               while (count--) {
+                                       rc = qdio_kick_outbound_q(q);
+                                       if (rc)
+                                               goto out;
+                               }
                        }
-
-               /* report CC=2 conditions synchronously */
-               if (q->qdio_error)
-                       __qdio_outbound_processing(q);
                goto out;
        }
 
@@ -1564,13 +1552,14 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
        /* try to fast requeue buffers */
        get_buf_state(q, prev_buf(bufnr), &state, 0);
        if (state != SLSB_CU_OUTPUT_PRIMED)
-               qdio_kick_outbound_q(q);
+               rc = qdio_kick_outbound_q(q);
        else {
                DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req");
                qdio_perf_stat_inc(&perf_stats.fast_requeue);
        }
 out:
        tasklet_schedule(&q->tasklet);
+       return rc;
 }
 
 /**
@@ -1609,14 +1598,12 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
                return -EBUSY;
 
        if (callflags & QDIO_FLAG_SYNC_INPUT)
-               handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr,
-                              count);
+               return handle_inbound(irq_ptr->input_qs[q_nr],
+                                     callflags, bufnr, count);
        else if (callflags & QDIO_FLAG_SYNC_OUTPUT)
-               handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr,
-                               count);
-       else
-               return -EINVAL;
-       return 0;
+               return handle_outbound(irq_ptr->output_qs[q_nr],
+                                      callflags, bufnr, count);
+       return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(do_QDIO);