diff options
author | Jan Glauber <jang@linux.vnet.ibm.com> | 2012-05-09 10:27:34 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-05-16 08:42:36 -0400 |
commit | 1549d13f4c5f0ca77b66bd725287d0b3f877eb6b (patch) | |
tree | 5ba439915cc4cceb8930a18e9adf2aba34adc82f /drivers/s390 | |
parent | 050276ab8ce9f30c1d2d74c42a349ed54701905f (diff) |
s390/qdio: Cleanup error handling to drivers
Various improvements of qdio error reporting to the
upper-layer drivers (qeth, zfcp):
- Split QDIO_ERROR_ACTIVATE_CHECK_CONDITION into:
QDIO_ERROR_ACTIVATE: qdio termination interrupt
QDIO_ERROR_GET_BUF_STATE: QIOASSIST eqbs error
QDIO_ERROR_SET_BUF_STATE: QIOASSIST sqbs error
Add QDIO_ERROR_FATAL / QDIO_ERROR_TEMPORARY masks
to ease recovery decision in upper-layer drivers.
- Don't (ab-)use qdio handler errors as return codes
for do_QDIO but use standard error codes:
-ENOBUFS: temporary target CC=2 condition
-EBUSY: unresolved SIGA-W CC=2 busy condition
-EIO: I/O error (CC=1, CC=3)
- Remove unneeded memory clobber from SIGA-R
- Remove EX_TABLE entry on SIGA-W, we want to see these errors
Reviewed-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 43 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 4 |
2 files changed, 24 insertions, 23 deletions
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 35c685c374e9..19902cdc6fac 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -63,7 +63,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask, | |||
63 | " ipm %0\n" | 63 | " ipm %0\n" |
64 | " srl %0,28\n" | 64 | " srl %0,28\n" |
65 | : "=d" (cc) | 65 | : "=d" (cc) |
66 | : "d" (__fc), "d" (__schid), "d" (__mask) : "cc", "memory"); | 66 | : "d" (__fc), "d" (__schid), "d" (__mask) : "cc"); |
67 | return cc; | 67 | return cc; |
68 | } | 68 | } |
69 | 69 | ||
@@ -74,7 +74,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask, | |||
74 | * @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer | 74 | * @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer |
75 | * @fc: function code to perform | 75 | * @fc: function code to perform |
76 | * | 76 | * |
77 | * Returns cc or QDIO_ERROR_SIGA_ACCESS_EXCEPTION. | 77 | * Returns condition code. |
78 | * Note: For IQDC unicast queues only the highest priority queue is processed. | 78 | * Note: For IQDC unicast queues only the highest priority queue is processed. |
79 | */ | 79 | */ |
80 | static inline int do_siga_output(unsigned long schid, unsigned long mask, | 80 | static inline int do_siga_output(unsigned long schid, unsigned long mask, |
@@ -85,18 +85,16 @@ static inline int do_siga_output(unsigned long schid, unsigned long mask, | |||
85 | register unsigned long __schid asm("1") = schid; | 85 | register unsigned long __schid asm("1") = schid; |
86 | register unsigned long __mask asm("2") = mask; | 86 | register unsigned long __mask asm("2") = mask; |
87 | register unsigned long __aob asm("3") = aob; | 87 | register unsigned long __aob asm("3") = aob; |
88 | int cc = QDIO_ERROR_SIGA_ACCESS_EXCEPTION; | 88 | int cc; |
89 | 89 | ||
90 | asm volatile( | 90 | asm volatile( |
91 | " siga 0\n" | 91 | " siga 0\n" |
92 | "0: ipm %0\n" | 92 | " ipm %0\n" |
93 | " srl %0,28\n" | 93 | " srl %0,28\n" |
94 | "1:\n" | 94 | : "=d" (cc), "+d" (__fc), "+d" (__aob) |
95 | EX_TABLE(0b, 1b) | 95 | : "d" (__schid), "d" (__mask) |
96 | : "+d" (cc), "+d" (__fc), "+d" (__schid), "+d" (__mask), | 96 | : "cc"); |
97 | "+d" (__aob) | 97 | *bb = __fc >> 31; |
98 | : : "cc", "memory"); | ||
99 | *bb = ((unsigned int) __fc) >> 31; | ||
100 | return cc; | 98 | return cc; |
101 | } | 99 | } |
102 | 100 | ||
@@ -167,7 +165,7 @@ again: | |||
167 | 165 | ||
168 | DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); | 166 | DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); |
169 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | 167 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); |
170 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, | 168 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_GET_BUF_STATE, |
171 | q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); | 169 | q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); |
172 | return 0; | 170 | return 0; |
173 | } | 171 | } |
@@ -215,7 +213,7 @@ again: | |||
215 | 213 | ||
216 | DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); | 214 | DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); |
217 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | 215 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); |
218 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, | 216 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_SET_BUF_STATE, |
219 | q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); | 217 | q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); |
220 | return 0; | 218 | return 0; |
221 | } | 219 | } |
@@ -313,7 +311,7 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, | |||
313 | cc = do_siga_sync(schid, output, input, fc); | 311 | cc = do_siga_sync(schid, output, input, fc); |
314 | if (unlikely(cc)) | 312 | if (unlikely(cc)) |
315 | DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); | 313 | DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); |
316 | return cc; | 314 | return (cc) ? -EIO : 0; |
317 | } | 315 | } |
318 | 316 | ||
319 | static inline int qdio_siga_sync_q(struct qdio_q *q) | 317 | static inline int qdio_siga_sync_q(struct qdio_q *q) |
@@ -384,7 +382,7 @@ static inline int qdio_siga_input(struct qdio_q *q) | |||
384 | cc = do_siga_input(schid, q->mask, fc); | 382 | cc = do_siga_input(schid, q->mask, fc); |
385 | if (unlikely(cc)) | 383 | if (unlikely(cc)) |
386 | DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); | 384 | DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); |
387 | return cc; | 385 | return (cc) ? -EIO : 0; |
388 | } | 386 | } |
389 | 387 | ||
390 | #define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0) | 388 | #define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0) |
@@ -443,7 +441,7 @@ static void process_buffer_error(struct qdio_q *q, int count) | |||
443 | unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT : | 441 | unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT : |
444 | SLSB_P_OUTPUT_NOT_INIT; | 442 | SLSB_P_OUTPUT_NOT_INIT; |
445 | 443 | ||
446 | q->qdio_error |= QDIO_ERROR_SLSB_STATE; | 444 | q->qdio_error = QDIO_ERROR_SLSB_STATE; |
447 | 445 | ||
448 | /* special handling for no target buffer empty */ | 446 | /* special handling for no target buffer empty */ |
449 | if ((!q->is_input_q && | 447 | if ((!q->is_input_q && |
@@ -575,7 +573,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q) | |||
575 | 573 | ||
576 | bufnr = get_inbound_buffer_frontier(q); | 574 | bufnr = get_inbound_buffer_frontier(q); |
577 | 575 | ||
578 | if ((bufnr != q->last_move) || q->qdio_error) { | 576 | if (bufnr != q->last_move) { |
579 | q->last_move = bufnr; | 577 | q->last_move = bufnr; |
580 | if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) | 578 | if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) |
581 | q->u.in.timestamp = get_clock(); | 579 | q->u.in.timestamp = get_clock(); |
@@ -863,7 +861,7 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) | |||
863 | 861 | ||
864 | bufnr = get_outbound_buffer_frontier(q); | 862 | bufnr = get_outbound_buffer_frontier(q); |
865 | 863 | ||
866 | if ((bufnr != q->last_move) || q->qdio_error) { | 864 | if (bufnr != q->last_move) { |
867 | q->last_move = bufnr; | 865 | q->last_move = bufnr; |
868 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); | 866 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); |
869 | return 1; | 867 | return 1; |
@@ -894,13 +892,16 @@ retry: | |||
894 | goto retry; | 892 | goto retry; |
895 | } | 893 | } |
896 | DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr); | 894 | DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr); |
897 | cc |= QDIO_ERROR_SIGA_BUSY; | 895 | cc = -EBUSY; |
898 | } else | 896 | } else { |
899 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); | 897 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); |
898 | cc = -ENOBUFS; | ||
899 | } | ||
900 | break; | 900 | break; |
901 | case 1: | 901 | case 1: |
902 | case 3: | 902 | case 3: |
903 | DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); | 903 | DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); |
904 | cc = -EIO; | ||
904 | break; | 905 | break; |
905 | } | 906 | } |
906 | if (retries) { | 907 | if (retries) { |
@@ -1090,7 +1091,7 @@ static void qdio_handle_activate_check(struct ccw_device *cdev, | |||
1090 | } | 1091 | } |
1091 | 1092 | ||
1092 | count = sub_buf(q->first_to_check, q->first_to_kick); | 1093 | count = sub_buf(q->first_to_check, q->first_to_kick); |
1093 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, | 1094 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE, |
1094 | q->nr, q->first_to_kick, count, irq_ptr->int_parm); | 1095 | q->nr, q->first_to_kick, count, irq_ptr->int_parm); |
1095 | no_handler: | 1096 | no_handler: |
1096 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); | 1097 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); |
@@ -1691,7 +1692,7 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, | |||
1691 | "do%02x b:%02x c:%02x", callflags, bufnr, count); | 1692 | "do%02x b:%02x c:%02x", callflags, bufnr, count); |
1692 | 1693 | ||
1693 | if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) | 1694 | if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) |
1694 | return -EBUSY; | 1695 | return -EIO; |
1695 | if (!count) | 1696 | if (!count) |
1696 | return 0; | 1697 | return 0; |
1697 | if (callflags & QDIO_FLAG_SYNC_INPUT) | 1698 | if (callflags & QDIO_FLAG_SYNC_INPUT) |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 8334dadc681d..c146877e8b7b 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -3339,7 +3339,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, | |||
3339 | if (rc) { | 3339 | if (rc) { |
3340 | queue->card->stats.tx_errors += count; | 3340 | queue->card->stats.tx_errors += count; |
3341 | /* ignore temporary SIGA errors without busy condition */ | 3341 | /* ignore temporary SIGA errors without busy condition */ |
3342 | if (rc == QDIO_ERROR_SIGA_TARGET) | 3342 | if (rc == -ENOBUFS) |
3343 | return; | 3343 | return; |
3344 | QETH_CARD_TEXT(queue->card, 2, "flushbuf"); | 3344 | QETH_CARD_TEXT(queue->card, 2, "flushbuf"); |
3345 | QETH_CARD_TEXT_(queue->card, 2, " q%d", queue->queue_no); | 3345 | QETH_CARD_TEXT_(queue->card, 2, " q%d", queue->queue_no); |
@@ -3533,7 +3533,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, | |||
3533 | int i; | 3533 | int i; |
3534 | 3534 | ||
3535 | QETH_CARD_TEXT(card, 6, "qdouhdl"); | 3535 | QETH_CARD_TEXT(card, 6, "qdouhdl"); |
3536 | if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) { | 3536 | if (qdio_error & QDIO_ERROR_FATAL) { |
3537 | QETH_CARD_TEXT(card, 2, "achkcond"); | 3537 | QETH_CARD_TEXT(card, 2, "achkcond"); |
3538 | netif_stop_queue(card->dev); | 3538 | netif_stop_queue(card->dev); |
3539 | qeth_schedule_recovery(card); | 3539 | qeth_schedule_recovery(card); |