diff options
author | Jan Glauber <jang@linux.vnet.ibm.com> | 2009-03-26 10:24:31 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-03-26 10:24:22 -0400 |
commit | d303b6fd858370c22d5c70c313669e3521a5f758 (patch) | |
tree | 3c8dd573bc3ea48af8f12c41e5f00358c09a579a /drivers/s390/net | |
parent | 9e890ad880be1dd98483313b2ec0e23fbd4e3792 (diff) |
[S390] qdio: report SIGA errors directly
Errors from SIGA instructions are stored in the per queue qdio_error
and reported back when the queue handler is called. That opens a race
when multiple error conditions occur simultanously.
Report SIGA errors immediately in the return value of do_QDIO so the
upper layer can react and SIGA errors no longer interfere with other
errors.
Move the SIGA error handling in qeth from the outbound handler to
qeth_flush_buffers.
Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Diffstat (limited to 'drivers/s390/net')
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 55 |
1 files changed, 17 insertions, 38 deletions
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d1b5bebea7fb..2489bcebf5ec 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -2693,40 +2693,21 @@ static int qeth_handle_send_error(struct qeth_card *card, | |||
2693 | struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err) | 2693 | struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err) |
2694 | { | 2694 | { |
2695 | int sbalf15 = buffer->buffer->element[15].flags & 0xff; | 2695 | int sbalf15 = buffer->buffer->element[15].flags & 0xff; |
2696 | int cc = qdio_err & 3; | ||
2697 | 2696 | ||
2698 | QETH_DBF_TEXT(TRACE, 6, "hdsnderr"); | 2697 | QETH_DBF_TEXT(TRACE, 6, "hdsnderr"); |
2699 | qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); | 2698 | qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); |
2700 | switch (cc) { | 2699 | |
2701 | case 0: | 2700 | if (!qdio_err) |
2702 | if (qdio_err) { | ||
2703 | QETH_DBF_TEXT(TRACE, 1, "lnkfail"); | ||
2704 | QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); | ||
2705 | QETH_DBF_TEXT_(TRACE, 1, "%04x %02x", | ||
2706 | (u16)qdio_err, (u8)sbalf15); | ||
2707 | return QETH_SEND_ERROR_LINK_FAILURE; | ||
2708 | } | ||
2709 | return QETH_SEND_ERROR_NONE; | 2701 | return QETH_SEND_ERROR_NONE; |
2710 | case 2: | 2702 | |
2711 | if (qdio_err & QDIO_ERROR_SIGA_BUSY) { | 2703 | if ((sbalf15 >= 15) && (sbalf15 <= 31)) |
2712 | QETH_DBF_TEXT(TRACE, 1, "SIGAcc2B"); | 2704 | return QETH_SEND_ERROR_RETRY; |
2713 | QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); | 2705 | |
2714 | return QETH_SEND_ERROR_KICK_IT; | 2706 | QETH_DBF_TEXT(TRACE, 1, "lnkfail"); |
2715 | } | 2707 | QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); |
2716 | if ((sbalf15 >= 15) && (sbalf15 <= 31)) | 2708 | QETH_DBF_TEXT_(TRACE, 1, "%04x %02x", |
2717 | return QETH_SEND_ERROR_RETRY; | 2709 | (u16)qdio_err, (u8)sbalf15); |
2718 | return QETH_SEND_ERROR_LINK_FAILURE; | 2710 | return QETH_SEND_ERROR_LINK_FAILURE; |
2719 | /* look at qdio_error and sbalf 15 */ | ||
2720 | case 1: | ||
2721 | QETH_DBF_TEXT(TRACE, 1, "SIGAcc1"); | ||
2722 | QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); | ||
2723 | return QETH_SEND_ERROR_LINK_FAILURE; | ||
2724 | case 3: | ||
2725 | default: | ||
2726 | QETH_DBF_TEXT(TRACE, 1, "SIGAcc3"); | ||
2727 | QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); | ||
2728 | return QETH_SEND_ERROR_KICK_IT; | ||
2729 | } | ||
2730 | } | 2711 | } |
2731 | 2712 | ||
2732 | /* | 2713 | /* |
@@ -2862,10 +2843,14 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, | |||
2862 | qeth_get_micros() - | 2843 | qeth_get_micros() - |
2863 | queue->card->perf_stats.outbound_do_qdio_start_time; | 2844 | queue->card->perf_stats.outbound_do_qdio_start_time; |
2864 | if (rc) { | 2845 | if (rc) { |
2846 | queue->card->stats.tx_errors += count; | ||
2847 | /* ignore temporary SIGA errors without busy condition */ | ||
2848 | if (rc == QDIO_ERROR_SIGA_TARGET) | ||
2849 | return; | ||
2865 | QETH_DBF_TEXT(TRACE, 2, "flushbuf"); | 2850 | QETH_DBF_TEXT(TRACE, 2, "flushbuf"); |
2866 | QETH_DBF_TEXT_(TRACE, 2, " err%d", rc); | 2851 | QETH_DBF_TEXT_(TRACE, 2, " err%d", rc); |
2867 | QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_DDEV_ID(queue->card)); | 2852 | QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_DDEV_ID(queue->card)); |
2868 | queue->card->stats.tx_errors += count; | 2853 | |
2869 | /* this must not happen under normal circumstances. if it | 2854 | /* this must not happen under normal circumstances. if it |
2870 | * happens something is really wrong -> recover */ | 2855 | * happens something is really wrong -> recover */ |
2871 | qeth_schedule_recovery(queue->card); | 2856 | qeth_schedule_recovery(queue->card); |
@@ -2940,13 +2925,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, | |||
2940 | } | 2925 | } |
2941 | for (i = first_element; i < (first_element + count); ++i) { | 2926 | for (i = first_element; i < (first_element + count); ++i) { |
2942 | buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; | 2927 | buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; |
2943 | /*we only handle the KICK_IT error by doing a recovery */ | 2928 | qeth_handle_send_error(card, buffer, qdio_error); |
2944 | if (qeth_handle_send_error(card, buffer, qdio_error) | ||
2945 | == QETH_SEND_ERROR_KICK_IT){ | ||
2946 | netif_stop_queue(card->dev); | ||
2947 | qeth_schedule_recovery(card); | ||
2948 | return; | ||
2949 | } | ||
2950 | qeth_clear_output_buffer(queue, buffer); | 2929 | qeth_clear_output_buffer(queue, buffer); |
2951 | } | 2930 | } |
2952 | atomic_sub(count, &queue->used_buffers); | 2931 | atomic_sub(count, &queue->used_buffers); |