Commit 1549d13f authored by Jan Glauber's avatar Jan Glauber Committed by Martin Schwidefsky

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: default avatarUrsula Braun <ursula.braun@de.ibm.com>
Signed-off-by: default avatarJan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 050276ab
...@@ -325,11 +325,13 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, ...@@ -325,11 +325,13 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
int, int, unsigned long); int, int, unsigned long);
/* qdio errors reported to the upper-layer program */ /* qdio errors reported to the upper-layer program */
#define QDIO_ERROR_SIGA_TARGET 0x02 #define QDIO_ERROR_ACTIVATE 0x0001
#define QDIO_ERROR_SIGA_ACCESS_EXCEPTION 0x10 #define QDIO_ERROR_GET_BUF_STATE 0x0002
#define QDIO_ERROR_SIGA_BUSY 0x20 #define QDIO_ERROR_SET_BUF_STATE 0x0004
#define QDIO_ERROR_ACTIVATE_CHECK_CONDITION 0x40 #define QDIO_ERROR_SLSB_STATE 0x0100
#define QDIO_ERROR_SLSB_STATE 0x80
#define QDIO_ERROR_FATAL 0x00ff
#define QDIO_ERROR_TEMPORARY 0xff00
/* for qdio_cleanup */ /* for qdio_cleanup */
#define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01 #define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01
......
...@@ -63,7 +63,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask, ...@@ -63,7 +63,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask,
" ipm %0\n" " ipm %0\n"
" srl %0,28\n" " srl %0,28\n"
: "=d" (cc) : "=d" (cc)
: "d" (__fc), "d" (__schid), "d" (__mask) : "cc", "memory"); : "d" (__fc), "d" (__schid), "d" (__mask) : "cc");
return cc; return cc;
} }
...@@ -74,7 +74,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask, ...@@ -74,7 +74,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask,
* @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer * @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer
* @fc: function code to perform * @fc: function code to perform
* *
* Returns cc or QDIO_ERROR_SIGA_ACCESS_EXCEPTION. * Returns condition code.
* Note: For IQDC unicast queues only the highest priority queue is processed. * Note: For IQDC unicast queues only the highest priority queue is processed.
*/ */
static inline int do_siga_output(unsigned long schid, unsigned long mask, 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,18 +85,16 @@ static inline int do_siga_output(unsigned long schid, unsigned long mask,
register unsigned long __schid asm("1") = schid; register unsigned long __schid asm("1") = schid;
register unsigned long __mask asm("2") = mask; register unsigned long __mask asm("2") = mask;
register unsigned long __aob asm("3") = aob; register unsigned long __aob asm("3") = aob;
int cc = QDIO_ERROR_SIGA_ACCESS_EXCEPTION; int cc;
asm volatile( asm volatile(
" siga 0\n" " siga 0\n"
"0: ipm %0\n" " ipm %0\n"
" srl %0,28\n" " srl %0,28\n"
"1:\n" : "=d" (cc), "+d" (__fc), "+d" (__aob)
EX_TABLE(0b, 1b) : "d" (__schid), "d" (__mask)
: "+d" (cc), "+d" (__fc), "+d" (__schid), "+d" (__mask), : "cc");
"+d" (__aob) *bb = __fc >> 31;
: : "cc", "memory");
*bb = ((unsigned int) __fc) >> 31;
return cc; return cc;
} }
...@@ -167,7 +165,7 @@ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, ...@@ -167,7 +165,7 @@ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); DBF_ERROR("%4x EQBS ERROR", SCH_NO(q));
DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, q->handler(q->irq_ptr->cdev, QDIO_ERROR_GET_BUF_STATE,
q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); q->nr, q->first_to_kick, count, q->irq_ptr->int_parm);
return 0; return 0;
} }
...@@ -215,7 +213,7 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, ...@@ -215,7 +213,7 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start,
DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); DBF_ERROR("%4x SQBS ERROR", SCH_NO(q));
DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, q->handler(q->irq_ptr->cdev, QDIO_ERROR_SET_BUF_STATE,
q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); q->nr, q->first_to_kick, count, q->irq_ptr->int_parm);
return 0; return 0;
} }
...@@ -313,7 +311,7 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, ...@@ -313,7 +311,7 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output,
cc = do_siga_sync(schid, output, input, fc); cc = do_siga_sync(schid, output, input, fc);
if (unlikely(cc)) if (unlikely(cc))
DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc);
return cc; return (cc) ? -EIO : 0;
} }
static inline int qdio_siga_sync_q(struct qdio_q *q) 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,7 +382,7 @@ static inline int qdio_siga_input(struct qdio_q *q)
cc = do_siga_input(schid, q->mask, fc); cc = do_siga_input(schid, q->mask, fc);
if (unlikely(cc)) if (unlikely(cc))
DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc);
return cc; return (cc) ? -EIO : 0;
} }
#define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0) #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,7 +441,7 @@ static void process_buffer_error(struct qdio_q *q, int count)
unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT : unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT :
SLSB_P_OUTPUT_NOT_INIT; SLSB_P_OUTPUT_NOT_INIT;
q->qdio_error |= QDIO_ERROR_SLSB_STATE; q->qdio_error = QDIO_ERROR_SLSB_STATE;
/* special handling for no target buffer empty */ /* special handling for no target buffer empty */
if ((!q->is_input_q && if ((!q->is_input_q &&
...@@ -575,7 +573,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q) ...@@ -575,7 +573,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q)
bufnr = get_inbound_buffer_frontier(q); bufnr = get_inbound_buffer_frontier(q);
if ((bufnr != q->last_move) || q->qdio_error) { if (bufnr != q->last_move) {
q->last_move = bufnr; q->last_move = bufnr;
if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR)
q->u.in.timestamp = get_clock(); q->u.in.timestamp = get_clock();
...@@ -863,7 +861,7 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) ...@@ -863,7 +861,7 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
bufnr = get_outbound_buffer_frontier(q); bufnr = get_outbound_buffer_frontier(q);
if ((bufnr != q->last_move) || q->qdio_error) { if (bufnr != q->last_move) {
q->last_move = bufnr; q->last_move = bufnr;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr);
return 1; return 1;
...@@ -894,13 +892,16 @@ static int qdio_kick_outbound_q(struct qdio_q *q, unsigned long aob) ...@@ -894,13 +892,16 @@ static int qdio_kick_outbound_q(struct qdio_q *q, unsigned long aob)
goto retry; goto retry;
} }
DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr); DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr);
cc |= QDIO_ERROR_SIGA_BUSY; cc = -EBUSY;
} else } else {
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
cc = -ENOBUFS;
}
break; break;
case 1: case 1:
case 3: case 3:
DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
cc = -EIO;
break; break;
} }
if (retries) { if (retries) {
...@@ -1090,7 +1091,7 @@ static void qdio_handle_activate_check(struct ccw_device *cdev, ...@@ -1090,7 +1091,7 @@ static void qdio_handle_activate_check(struct ccw_device *cdev,
} }
count = sub_buf(q->first_to_check, q->first_to_kick); count = sub_buf(q->first_to_check, q->first_to_kick);
q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE,
q->nr, q->first_to_kick, count, irq_ptr->int_parm); q->nr, q->first_to_kick, count, irq_ptr->int_parm);
no_handler: no_handler:
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED);
...@@ -1691,7 +1692,7 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, ...@@ -1691,7 +1692,7 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
"do%02x b:%02x c:%02x", callflags, bufnr, count); "do%02x b:%02x c:%02x", callflags, bufnr, count);
if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)
return -EBUSY; return -EIO;
if (!count) if (!count)
return 0; return 0;
if (callflags & QDIO_FLAG_SYNC_INPUT) if (callflags & QDIO_FLAG_SYNC_INPUT)
......
...@@ -3339,7 +3339,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, ...@@ -3339,7 +3339,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
if (rc) { if (rc) {
queue->card->stats.tx_errors += count; queue->card->stats.tx_errors += count;
/* ignore temporary SIGA errors without busy condition */ /* ignore temporary SIGA errors without busy condition */
if (rc == QDIO_ERROR_SIGA_TARGET) if (rc == -ENOBUFS)
return; return;
QETH_CARD_TEXT(queue->card, 2, "flushbuf"); QETH_CARD_TEXT(queue->card, 2, "flushbuf");
QETH_CARD_TEXT_(queue->card, 2, " q%d", queue->queue_no); 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,7 +3533,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
int i; int i;
QETH_CARD_TEXT(card, 6, "qdouhdl"); QETH_CARD_TEXT(card, 6, "qdouhdl");
if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) { if (qdio_error & QDIO_ERROR_FATAL) {
QETH_CARD_TEXT(card, 2, "achkcond"); QETH_CARD_TEXT(card, 2, "achkcond");
netif_stop_queue(card->dev); netif_stop_queue(card->dev);
qeth_schedule_recovery(card); qeth_schedule_recovery(card);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment