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/cio/qdio_main.c | |
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/cio/qdio_main.c')
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 73 |
1 files changed, 30 insertions, 43 deletions
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 | ||
709 | static void qdio_kick_outbound_q(struct qdio_q *q) | 709 | static 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 | ||
742 | static void qdio_kick_outbound_handler(struct qdio_q *q) | 739 | static 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 | ||
767 | static void __qdio_outbound_processing(struct qdio_q *q) | 764 | static 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 | */ |
1460 | static void handle_inbound(struct qdio_q *q, unsigned int callflags, | 1451 | static 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 | */ |
1516 | static void handle_outbound(struct qdio_q *q, unsigned int callflags, | 1505 | static 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 | } |
1572 | out: | 1560 | out: |
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 | } |
1621 | EXPORT_SYMBOL_GPL(do_QDIO); | 1608 | EXPORT_SYMBOL_GPL(do_QDIO); |
1622 | 1609 | ||