aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorJan Glauber <jang@linux.vnet.ibm.com>2008-12-25 07:38:48 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-12-25 07:39:00 -0500
commit7a0b4cbc7d7d99763511b488b08bbc2607ddd1e3 (patch)
tree96344f73eb9d802b0f488b7d086c8094b93635f8 /drivers/s390
parent50f769df1c4bea766c4eb927eae35728fb93e305 (diff)
[S390] qdio: fix error reporting for hipersockets
Hipersocket connections can encounter temporary busy conditions. In case of the busy bit set we retry the SIGA operation immediatelly. If the busy condition still persists after 100 ms we fail and report the error to the upper layer. The second stage retry logic is removed. In case of ongoing busy conditions the upper layer needs to reset the connection. The reporting of a SIGA error is now done synchronously to allow the network driver to requeue the buffers. Also no error trace is created for the temporary SIGA errors so the error message view is not flooded. 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.h8
-rw-r--r--drivers/s390/cio/qdio_main.c150
-rw-r--r--drivers/s390/cio/qdio_setup.c1
3 files changed, 56 insertions, 103 deletions
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index c60f2566d28..42f2b09631b 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -14,7 +14,6 @@
14#include "chsc.h" 14#include "chsc.h"
15 15
16#define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */ 16#define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */
17#define QDIO_BUSY_BIT_GIVE_UP 2000000 /* 2 seconds = eternity */
18#define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */ 17#define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */
19 18
20/* 19/*
@@ -195,12 +194,6 @@ struct qdio_input_q {
195}; 194};
196 195
197struct qdio_output_q { 196struct qdio_output_q {
198 /* failed siga-w attempts*/
199 atomic_t busy_siga_counter;
200
201 /* start time of busy condition */
202 u64 timestamp;
203
204 /* PCIs are enabled for the queue */ 197 /* PCIs are enabled for the queue */
205 int pci_out_enabled; 198 int pci_out_enabled;
206 199
@@ -251,6 +244,7 @@ struct qdio_q {
251 244
252 struct qdio_irq *irq_ptr; 245 struct qdio_irq *irq_ptr;
253 struct tasklet_struct tasklet; 246 struct tasklet_struct tasklet;
247 spinlock_t lock;
254 248
255 /* error condition during a data transfer */ 249 /* error condition during a data transfer */
256 unsigned int qdio_error; 250 unsigned int qdio_error;
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 0b4c09cf6a4..744f928a59e 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -74,7 +74,7 @@ static inline int do_siga_input(struct subchannel_id schid, unsigned int mask)
74 * Note: For IQDC unicast queues only the highest priority queue is processed. 74 * Note: For IQDC unicast queues only the highest priority queue is processed.
75 */ 75 */
76static inline int do_siga_output(unsigned long schid, unsigned long mask, 76static inline int do_siga_output(unsigned long schid, unsigned long mask,
77 u32 *bb, unsigned int fc) 77 unsigned int *bb, unsigned int fc)
78{ 78{
79 register unsigned long __fc asm("0") = fc; 79 register unsigned long __fc asm("0") = fc;
80 register unsigned long __schid asm("1") = schid; 80 register unsigned long __schid asm("1") = schid;
@@ -284,8 +284,7 @@ static int qdio_siga_sync(struct qdio_q *q, unsigned int output,
284 if (!need_siga_sync(q)) 284 if (!need_siga_sync(q))
285 return 0; 285 return 0;
286 286
287 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:"); 287 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr);
288 DBF_DEV_HEX(DBF_INFO, q->irq_ptr, q, sizeof(void *));
289 qdio_perf_stat_inc(&perf_stats.siga_sync); 288 qdio_perf_stat_inc(&perf_stats.siga_sync);
290 289
291 cc = do_siga_sync(q->irq_ptr->schid, output, input); 290 cc = do_siga_sync(q->irq_ptr->schid, output, input);
@@ -312,46 +311,37 @@ static inline int qdio_siga_sync_all(struct qdio_q *q)
312 return qdio_siga_sync(q, ~0U, ~0U); 311 return qdio_siga_sync(q, ~0U, ~0U);
313} 312}
314 313
315static inline int qdio_do_siga_output(struct qdio_q *q, unsigned int *busy_bit) 314static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
316{ 315{
317 unsigned int fc = 0;
318 unsigned long schid; 316 unsigned long schid;
317 unsigned int fc = 0;
318 u64 start_time = 0;
319 int cc;
319 320
320 if (q->u.out.use_enh_siga) { 321 if (q->u.out.use_enh_siga)
321 fc = 3; 322 fc = 3;
322 } 323
323 if (!is_qebsm(q)) 324 if (is_qebsm(q)) {
324 schid = *((u32 *)&q->irq_ptr->schid);
325 else {
326 schid = q->irq_ptr->sch_token; 325 schid = q->irq_ptr->sch_token;
327 fc |= 0x80; 326 fc |= 0x80;
328 } 327 }
329 return do_siga_output(schid, q->mask, busy_bit, fc); 328 else
330} 329 schid = *((u32 *)&q->irq_ptr->schid);
331
332static int qdio_siga_output(struct qdio_q *q)
333{
334 int cc;
335 u32 busy_bit;
336 u64 start_time = 0;
337 330
338 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
339 qdio_perf_stat_inc(&perf_stats.siga_out);
340again: 331again:
341 cc = qdio_do_siga_output(q, &busy_bit); 332 cc = do_siga_output(schid, q->mask, busy_bit, fc);
342 if (queue_type(q) == QDIO_IQDIO_QFMT && cc == 2 && busy_bit) { 333
343 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w bb:%2d", q->nr); 334 /* hipersocket busy condition */
335 if (*busy_bit) {
336 WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
344 337
345 if (!start_time) 338 if (!start_time) {
346 start_time = get_usecs(); 339 start_time = get_usecs();
347 else if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) 340 goto again;
341 }
342 if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE)
348 goto again; 343 goto again;
349 } 344 }
350
351 if (cc == 2 && busy_bit)
352 cc |= QDIO_ERROR_SIGA_BUSY;
353 if (cc)
354 DBF_ERROR("%4x SIGA-W:%2d", SCH_NO(q), cc);
355 return cc; 345 return cc;
356} 346}
357 347
@@ -399,7 +389,7 @@ inline void qdio_stop_polling(struct qdio_q *q)
399 389
400static void announce_buffer_error(struct qdio_q *q, int count) 390static void announce_buffer_error(struct qdio_q *q, int count)
401{ 391{
402 q->qdio_error = QDIO_ERROR_SLSB_STATE; 392 q->qdio_error |= QDIO_ERROR_SLSB_STATE;
403 393
404 /* special handling for no target buffer empty */ 394 /* special handling for no target buffer empty */
405 if ((!q->is_input_q && 395 if ((!q->is_input_q &&
@@ -716,68 +706,36 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
716 return 0; 706 return 0;
717} 707}
718 708
719/*
720 * VM could present us cc=2 and busy bit set on SIGA-write
721 * during reconfiguration of their Guest LAN (only in iqdio mode,
722 * otherwise qdio is asynchronous and cc=2 and busy bit there will take
723 * the queues down immediately).
724 *
725 * Therefore qdio_siga_output will try for a short time constantly,
726 * if such a condition occurs. If it doesn't change, it will
727 * increase the busy_siga_counter and save the timestamp, and
728 * schedule the queue for later processing. qdio_outbound_processing
729 * will check out the counter. If non-zero, it will call qdio_kick_outbound_q
730 * as often as the value of the counter. This will attempt further SIGA
731 * instructions. For each successful SIGA, the counter is
732 * decreased, for failing SIGAs the counter remains the same, after
733 * all. After some time of no movement, qdio_kick_outbound_q will
734 * finally fail and reflect corresponding error codes to call
735 * the upper layer module and have it take the queues down.
736 *
737 * Note that this is a change from the original HiperSockets design
738 * (saying cc=2 and busy bit means take the queues down), but in
739 * these days Guest LAN didn't exist... excessive cc=2 with busy bit
740 * conditions will still take the queues down, but the threshold is
741 * higher due to the Guest LAN environment.
742 *
743 * Called from outbound tasklet and do_QDIO handler.
744 */
745static void qdio_kick_outbound_q(struct qdio_q *q) 709static void qdio_kick_outbound_q(struct qdio_q *q)
746{ 710{
747 int rc; 711 unsigned int busy_bit;
748 712 int cc;
749 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickoutq:%1d", q->nr);
750 713
751 if (!need_siga_out(q)) 714 if (!need_siga_out(q))
752 return; 715 return;
753 716
754 rc = qdio_siga_output(q); 717 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
755 switch (rc) { 718 qdio_perf_stat_inc(&perf_stats.siga_out);
719
720 cc = qdio_siga_output(q, &busy_bit);
721 switch (cc) {
756 case 0: 722 case 0:
757 /* TODO: improve error handling for CC=0 case */
758 if (q->u.out.timestamp)
759 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "cc2 rslv:%4x",
760 atomic_read(&q->u.out.busy_siga_counter));
761 /* went smooth this time, reset timestamp */
762 q->u.out.timestamp = 0;
763 break; 723 break;
764 /* cc=2 and busy bit */ 724 case 2:
765 case (2 | QDIO_ERROR_SIGA_BUSY): 725 if (busy_bit) {
766 atomic_inc(&q->u.out.busy_siga_counter); 726 DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
767 727 q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY;
768 /* if the last siga was successful, save timestamp here */ 728 } else {
769 if (!q->u.out.timestamp) 729 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d",
770 q->u.out.timestamp = get_usecs(); 730 q->nr);
771 731 q->qdio_error = cc;
772 /* if we're in time, don't touch qdio_error */
773 if (get_usecs() - q->u.out.timestamp < QDIO_BUSY_BIT_GIVE_UP) {
774 tasklet_schedule(&q->tasklet);
775 break;
776 } 732 }
777 DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); 733 break;
778 default: 734 case 1:
779 /* for plain cc=1, 2 or 3 */ 735 case 3:
780 q->qdio_error = rc; 736 DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
737 q->qdio_error = cc;
738 break;
781 } 739 }
782} 740}
783 741
@@ -808,22 +766,18 @@ static void qdio_kick_outbound_handler(struct qdio_q *q)
808 766
809static void __qdio_outbound_processing(struct qdio_q *q) 767static void __qdio_outbound_processing(struct qdio_q *q)
810{ 768{
811 int siga_attempts; 769 unsigned long flags;
812 770
813 qdio_perf_stat_inc(&perf_stats.tasklet_outbound); 771 qdio_perf_stat_inc(&perf_stats.tasklet_outbound);
814 772 spin_lock_irqsave(&q->lock, flags);
815 /* see comment in qdio_kick_outbound_q */
816 siga_attempts = atomic_read(&q->u.out.busy_siga_counter);
817 while (siga_attempts--) {
818 atomic_dec(&q->u.out.busy_siga_counter);
819 qdio_kick_outbound_q(q);
820 }
821 773
822 BUG_ON(atomic_read(&q->nr_buf_used) < 0); 774 BUG_ON(atomic_read(&q->nr_buf_used) < 0);
823 775
824 if (qdio_outbound_q_moved(q)) 776 if (qdio_outbound_q_moved(q))
825 qdio_kick_outbound_handler(q); 777 qdio_kick_outbound_handler(q);
826 778
779 spin_unlock_irqrestore(&q->lock, flags);
780
827 if (queue_type(q) == QDIO_ZFCP_QFMT) { 781 if (queue_type(q) == QDIO_ZFCP_QFMT) {
828 if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) 782 if (!pci_out_supported(q) && !qdio_outbound_q_done(q))
829 tasklet_schedule(&q->tasklet); 783 tasklet_schedule(&q->tasklet);
@@ -1491,7 +1445,7 @@ static inline int buf_in_between(int bufnr, int start, int count)
1491static void handle_inbound(struct qdio_q *q, unsigned int callflags, 1445static void handle_inbound(struct qdio_q *q, unsigned int callflags,
1492 int bufnr, int count) 1446 int bufnr, int count)
1493{ 1447{
1494 int used, rc, diff; 1448 int used, cc, diff;
1495 1449
1496 if (!q->u.in.polling) 1450 if (!q->u.in.polling)
1497 goto set; 1451 goto set;
@@ -1532,9 +1486,9 @@ set:
1532 return; 1486 return;
1533 1487
1534 if (need_siga_in(q)) { 1488 if (need_siga_in(q)) {
1535 rc = qdio_siga_input(q); 1489 cc = qdio_siga_input(q);
1536 if (rc) 1490 if (cc)
1537 q->qdio_error = rc; 1491 q->qdio_error = cc;
1538 } 1492 }
1539} 1493}
1540 1494
@@ -1581,6 +1535,10 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
1581 while (count--) 1535 while (count--)
1582 qdio_kick_outbound_q(q); 1536 qdio_kick_outbound_q(q);
1583 } 1537 }
1538
1539 /* report CC=2 conditions synchronously */
1540 if (q->qdio_error)
1541 __qdio_outbound_processing(q);
1584 goto out; 1542 goto out;
1585 } 1543 }
1586 1544
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 18d54fc21ce..c08356b95bf 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -117,6 +117,7 @@ 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);
120} 121}
121 122
122static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, 123static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,