aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorJan Glauber <jang@linux.vnet.ibm.com>2009-03-26 10:24:31 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-03-26 10:24:22 -0400
commitd303b6fd858370c22d5c70c313669e3521a5f758 (patch)
tree3c8dd573bc3ea48af8f12c41e5f00358c09a579a /drivers/s390
parent9e890ad880be1dd98483313b2ec0e23fbd4e3792 (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')
-rw-r--r--drivers/s390/cio/qdio.h1
-rw-r--r--drivers/s390/cio/qdio_main.c73
-rw-r--r--drivers/s390/cio/qdio_setup.c1
-rw-r--r--drivers/s390/net/qeth_core_main.c55
4 files changed, 47 insertions, 83 deletions
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 57807f5ffe84..41171d741f38 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -247,7 +247,6 @@ struct qdio_q {
247 247
248 struct qdio_irq *irq_ptr; 248 struct qdio_irq *irq_ptr;
249 struct tasklet_struct tasklet; 249 struct tasklet_struct tasklet;
250 spinlock_t lock;
251 250
252 /* error condition during a data transfer */ 251 /* error condition during a data transfer */
253 unsigned int qdio_error; 252 unsigned int qdio_error;
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 31b9318149ba..e53ac67e1e48 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -706,13 +706,13 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
706 return 0; 706 return 0;
707} 707}
708 708
709static void qdio_kick_outbound_q(struct qdio_q *q) 709static int qdio_kick_outbound_q(struct qdio_q *q)
710{ 710{
711 unsigned int busy_bit; 711 unsigned int busy_bit;
712 int cc; 712 int cc;
713 713
714 if (!need_siga_out(q)) 714 if (!need_siga_out(q))
715 return; 715 return 0;
716 716
717 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); 717 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
718 qdio_perf_stat_inc(&perf_stats.siga_out); 718 qdio_perf_stat_inc(&perf_stats.siga_out);
@@ -724,19 +724,16 @@ static void qdio_kick_outbound_q(struct qdio_q *q)
724 case 2: 724 case 2:
725 if (busy_bit) { 725 if (busy_bit) {
726 DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); 726 DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
727 q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY; 727 cc |= QDIO_ERROR_SIGA_BUSY;
728 } else { 728 } else
729 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", 729 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
730 q->nr);
731 q->qdio_error = cc;
732 }
733 break; 730 break;
734 case 1: 731 case 1:
735 case 3: 732 case 3:
736 DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); 733 DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
737 q->qdio_error = cc;
738 break; 734 break;
739 } 735 }
736 return cc;
740} 737}
741 738
742static void qdio_kick_outbound_handler(struct qdio_q *q) 739static void qdio_kick_outbound_handler(struct qdio_q *q)
@@ -766,18 +763,12 @@ static void qdio_kick_outbound_handler(struct qdio_q *q)
766 763
767static void __qdio_outbound_processing(struct qdio_q *q) 764static void __qdio_outbound_processing(struct qdio_q *q)
768{ 765{
769 unsigned long flags;
770
771 qdio_perf_stat_inc(&perf_stats.tasklet_outbound); 766 qdio_perf_stat_inc(&perf_stats.tasklet_outbound);
772 spin_lock_irqsave(&q->lock, flags);
773
774 BUG_ON(atomic_read(&q->nr_buf_used) < 0); 767 BUG_ON(atomic_read(&q->nr_buf_used) < 0);
775 768
776 if (qdio_outbound_q_moved(q)) 769 if (qdio_outbound_q_moved(q))
777 qdio_kick_outbound_handler(q); 770 qdio_kick_outbound_handler(q);
778 771
779 spin_unlock_irqrestore(&q->lock, flags);
780
781 if (queue_type(q) == QDIO_ZFCP_QFMT) 772 if (queue_type(q) == QDIO_ZFCP_QFMT)
782 if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) 773 if (!pci_out_supported(q) && !qdio_outbound_q_done(q))
783 goto sched; 774 goto sched;
@@ -1457,10 +1448,10 @@ static inline int buf_in_between(int bufnr, int start, int count)
1457 * @bufnr: first buffer to process 1448 * @bufnr: first buffer to process
1458 * @count: how many buffers are emptied 1449 * @count: how many buffers are emptied
1459 */ 1450 */
1460static void handle_inbound(struct qdio_q *q, unsigned int callflags, 1451static int handle_inbound(struct qdio_q *q, unsigned int callflags,
1461 int bufnr, int count) 1452 int bufnr, int count)
1462{ 1453{
1463 int used, cc, diff; 1454 int used, diff;
1464 1455
1465 if (!q->u.in.polling) 1456 if (!q->u.in.polling)
1466 goto set; 1457 goto set;
@@ -1497,13 +1488,11 @@ set:
1497 1488
1498 /* no need to signal as long as the adapter had free buffers */ 1489 /* no need to signal as long as the adapter had free buffers */
1499 if (used) 1490 if (used)
1500 return; 1491 return 0;
1501 1492
1502 if (need_siga_in(q)) { 1493 if (need_siga_in(q))
1503 cc = qdio_siga_input(q); 1494 return qdio_siga_input(q);
1504 if (cc) 1495 return 0;
1505 q->qdio_error = cc;
1506 }
1507} 1496}
1508 1497
1509/** 1498/**
@@ -1513,11 +1502,11 @@ set:
1513 * @bufnr: first buffer to process 1502 * @bufnr: first buffer to process
1514 * @count: how many buffers are filled 1503 * @count: how many buffers are filled
1515 */ 1504 */
1516static void handle_outbound(struct qdio_q *q, unsigned int callflags, 1505static int handle_outbound(struct qdio_q *q, unsigned int callflags,
1517 int bufnr, int count) 1506 int bufnr, int count)
1518{ 1507{
1519 unsigned char state; 1508 unsigned char state;
1520 int used; 1509 int used, rc = 0;
1521 1510
1522 qdio_perf_stat_inc(&perf_stats.outbound_handler); 1511 qdio_perf_stat_inc(&perf_stats.outbound_handler);
1523 1512
@@ -1532,27 +1521,26 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
1532 1521
1533 if (queue_type(q) == QDIO_IQDIO_QFMT) { 1522 if (queue_type(q) == QDIO_IQDIO_QFMT) {
1534 if (multicast_outbound(q)) 1523 if (multicast_outbound(q))
1535 qdio_kick_outbound_q(q); 1524 rc = qdio_kick_outbound_q(q);
1536 else 1525 else
1537 if ((q->irq_ptr->ssqd_desc.mmwc > 1) && 1526 if ((q->irq_ptr->ssqd_desc.mmwc > 1) &&
1538 (count > 1) && 1527 (count > 1) &&
1539 (count <= q->irq_ptr->ssqd_desc.mmwc)) { 1528 (count <= q->irq_ptr->ssqd_desc.mmwc)) {
1540 /* exploit enhanced SIGA */ 1529 /* exploit enhanced SIGA */
1541 q->u.out.use_enh_siga = 1; 1530 q->u.out.use_enh_siga = 1;
1542 qdio_kick_outbound_q(q); 1531 rc = qdio_kick_outbound_q(q);
1543 } else { 1532 } else {
1544 /* 1533 /*
1545 * One siga-w per buffer required for unicast 1534 * One siga-w per buffer required for unicast
1546 * HiperSockets. 1535 * HiperSockets.
1547 */ 1536 */
1548 q->u.out.use_enh_siga = 0; 1537 q->u.out.use_enh_siga = 0;
1549 while (count--) 1538 while (count--) {
1550 qdio_kick_outbound_q(q); 1539 rc = qdio_kick_outbound_q(q);
1540 if (rc)
1541 goto out;
1542 }
1551 } 1543 }
1552
1553 /* report CC=2 conditions synchronously */
1554 if (q->qdio_error)
1555 __qdio_outbound_processing(q);
1556 goto out; 1544 goto out;
1557 } 1545 }
1558 1546
@@ -1564,13 +1552,14 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
1564 /* try to fast requeue buffers */ 1552 /* try to fast requeue buffers */
1565 get_buf_state(q, prev_buf(bufnr), &state, 0); 1553 get_buf_state(q, prev_buf(bufnr), &state, 0);
1566 if (state != SLSB_CU_OUTPUT_PRIMED) 1554 if (state != SLSB_CU_OUTPUT_PRIMED)
1567 qdio_kick_outbound_q(q); 1555 rc = qdio_kick_outbound_q(q);
1568 else { 1556 else {
1569 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req"); 1557 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req");
1570 qdio_perf_stat_inc(&perf_stats.fast_requeue); 1558 qdio_perf_stat_inc(&perf_stats.fast_requeue);
1571 } 1559 }
1572out: 1560out:
1573 tasklet_schedule(&q->tasklet); 1561 tasklet_schedule(&q->tasklet);
1562 return rc;
1574} 1563}
1575 1564
1576/** 1565/**
@@ -1609,14 +1598,12 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
1609 return -EBUSY; 1598 return -EBUSY;
1610 1599
1611 if (callflags & QDIO_FLAG_SYNC_INPUT) 1600 if (callflags & QDIO_FLAG_SYNC_INPUT)
1612 handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr, 1601 return handle_inbound(irq_ptr->input_qs[q_nr],
1613 count); 1602 callflags, bufnr, count);
1614 else if (callflags & QDIO_FLAG_SYNC_OUTPUT) 1603 else if (callflags & QDIO_FLAG_SYNC_OUTPUT)
1615 handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr, 1604 return handle_outbound(irq_ptr->output_qs[q_nr],
1616 count); 1605 callflags, bufnr, count);
1617 else 1606 return -EINVAL;
1618 return -EINVAL;
1619 return 0;
1620} 1607}
1621EXPORT_SYMBOL_GPL(do_QDIO); 1608EXPORT_SYMBOL_GPL(do_QDIO);
1622 1609
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index c08356b95bf5..18d54fc21ce9 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -117,7 +117,6 @@ static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr,
117 q->mask = 1 << (31 - i); 117 q->mask = 1 << (31 - i);
118 q->nr = i; 118 q->nr = i;
119 q->handler = handler; 119 q->handler = handler;
120 spin_lock_init(&q->lock);
121} 120}
122 121
123static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, 122static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
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);