diff options
author | Einar Lueck <elelueck@de.ibm.com> | 2011-12-19 17:56:36 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-20 14:05:04 -0500 |
commit | 72861ae792c2263bd1058dd3b034e0bf84a676c1 (patch) | |
tree | ebc71e3c899f075d5257722efcb26c58703b2c3e /drivers/s390 | |
parent | 3f36b890dea7c2fc2fe25fb507552a46a226048a (diff) |
qeth: recovery through asynchronous delivery
If recovery is triggered in presence of pending asynchronous
deliveries of storage blocks we do a forced cleanup after
the corresponding tasklets are completely stopped and trigger
appropriate notifications for the correspondingerror state.
Signed-off-by: Einar Lueck <elelueck@de.ibm.com>
Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 34 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 5 |
2 files changed, 34 insertions, 5 deletions
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 680040572bcb..4fae1dc19951 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -66,7 +66,7 @@ static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf); | |||
66 | static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, | 66 | static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, |
67 | struct qeth_qdio_out_buffer *buf, | 67 | struct qeth_qdio_out_buffer *buf, |
68 | enum qeth_qdio_buffer_states newbufstate); | 68 | enum qeth_qdio_buffer_states newbufstate); |
69 | 69 | static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int); | |
70 | 70 | ||
71 | static inline const char *qeth_get_cardname(struct qeth_card *card) | 71 | static inline const char *qeth_get_cardname(struct qeth_card *card) |
72 | { | 72 | { |
@@ -363,6 +363,9 @@ static inline enum iucv_tx_notify qeth_compute_cq_notification(int sbalf15, | |||
363 | static inline void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, | 363 | static inline void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, |
364 | int bidx, int forced_cleanup) | 364 | int bidx, int forced_cleanup) |
365 | { | 365 | { |
366 | if (q->card->options.cq != QETH_CQ_ENABLED) | ||
367 | return; | ||
368 | |||
366 | if (q->bufs[bidx]->next_pending != NULL) { | 369 | if (q->bufs[bidx]->next_pending != NULL) { |
367 | struct qeth_qdio_out_buffer *head = q->bufs[bidx]; | 370 | struct qeth_qdio_out_buffer *head = q->bufs[bidx]; |
368 | struct qeth_qdio_out_buffer *c = q->bufs[bidx]->next_pending; | 371 | struct qeth_qdio_out_buffer *c = q->bufs[bidx]->next_pending; |
@@ -390,6 +393,13 @@ static inline void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, | |||
390 | 393 | ||
391 | } | 394 | } |
392 | } | 395 | } |
396 | if (forced_cleanup && (atomic_read(&(q->bufs[bidx]->state)) == | ||
397 | QETH_QDIO_BUF_HANDLED_DELAYED)) { | ||
398 | /* for recovery situations */ | ||
399 | q->bufs[bidx]->aob = q->bufstates[bidx].aob; | ||
400 | qeth_init_qdio_out_buf(q, bidx); | ||
401 | QETH_CARD_TEXT(q->card, 2, "clprecov"); | ||
402 | } | ||
393 | } | 403 | } |
394 | 404 | ||
395 | 405 | ||
@@ -412,7 +422,6 @@ static inline void qeth_qdio_handle_aob(struct qeth_card *card, | |||
412 | notification = TX_NOTIFY_OK; | 422 | notification = TX_NOTIFY_OK; |
413 | } else { | 423 | } else { |
414 | BUG_ON(atomic_read(&buffer->state) != QETH_QDIO_BUF_PENDING); | 424 | BUG_ON(atomic_read(&buffer->state) != QETH_QDIO_BUF_PENDING); |
415 | |||
416 | atomic_set(&buffer->state, QETH_QDIO_BUF_IN_CQ); | 425 | atomic_set(&buffer->state, QETH_QDIO_BUF_IN_CQ); |
417 | notification = TX_NOTIFY_DELAYED_OK; | 426 | notification = TX_NOTIFY_DELAYED_OK; |
418 | } | 427 | } |
@@ -425,7 +434,8 @@ static inline void qeth_qdio_handle_aob(struct qeth_card *card, | |||
425 | 434 | ||
426 | buffer->aob = NULL; | 435 | buffer->aob = NULL; |
427 | qeth_clear_output_buffer(buffer->q, buffer, | 436 | qeth_clear_output_buffer(buffer->q, buffer, |
428 | QETH_QDIO_BUF_HANDLED_DELAYED); | 437 | QETH_QDIO_BUF_HANDLED_DELAYED); |
438 | |||
429 | /* from here on: do not touch buffer anymore */ | 439 | /* from here on: do not touch buffer anymore */ |
430 | qdio_release_aob(aob); | 440 | qdio_release_aob(aob); |
431 | } | 441 | } |
@@ -1113,11 +1123,25 @@ out: | |||
1113 | static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) | 1123 | static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) |
1114 | { | 1124 | { |
1115 | struct sk_buff *skb; | 1125 | struct sk_buff *skb; |
1126 | struct iucv_sock *iucv; | ||
1127 | int notify_general_error = 0; | ||
1128 | |||
1129 | if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING) | ||
1130 | notify_general_error = 1; | ||
1131 | |||
1132 | /* release may never happen from within CQ tasklet scope */ | ||
1133 | BUG_ON(atomic_read(&buf->state) == QETH_QDIO_BUF_IN_CQ); | ||
1116 | 1134 | ||
1117 | skb = skb_dequeue(&buf->skb_list); | 1135 | skb = skb_dequeue(&buf->skb_list); |
1118 | while (skb) { | 1136 | while (skb) { |
1119 | QETH_CARD_TEXT(buf->q->card, 5, "skbr"); | 1137 | QETH_CARD_TEXT(buf->q->card, 5, "skbr"); |
1120 | QETH_CARD_TEXT_(buf->q->card, 5, "%lx", (long) skb); | 1138 | QETH_CARD_TEXT_(buf->q->card, 5, "%lx", (long) skb); |
1139 | if (notify_general_error && skb->protocol == ETH_P_AF_IUCV) { | ||
1140 | if (skb->sk) { | ||
1141 | iucv = iucv_sk(skb->sk); | ||
1142 | iucv->sk_txnotify(skb, TX_NOTIFY_GENERALERROR); | ||
1143 | } | ||
1144 | } | ||
1121 | atomic_dec(&skb->users); | 1145 | atomic_dec(&skb->users); |
1122 | dev_kfree_skb_any(skb); | 1146 | dev_kfree_skb_any(skb); |
1123 | skb = skb_dequeue(&buf->skb_list); | 1147 | skb = skb_dequeue(&buf->skb_list); |
@@ -1160,7 +1184,7 @@ static void qeth_clear_outq_buffers(struct qeth_qdio_out_q *q, int free) | |||
1160 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { | 1184 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { |
1161 | if (!q->bufs[j]) | 1185 | if (!q->bufs[j]) |
1162 | continue; | 1186 | continue; |
1163 | qeth_cleanup_handled_pending(q, j, free); | 1187 | qeth_cleanup_handled_pending(q, j, 1); |
1164 | qeth_clear_output_buffer(q, q->bufs[j], QETH_QDIO_BUF_EMPTY); | 1188 | qeth_clear_output_buffer(q, q->bufs[j], QETH_QDIO_BUF_EMPTY); |
1165 | if (free) { | 1189 | if (free) { |
1166 | kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[j]); | 1190 | kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[j]); |
@@ -1207,7 +1231,7 @@ static void qeth_free_qdio_buffers(struct qeth_card *card) | |||
1207 | qeth_free_cq(card); | 1231 | qeth_free_cq(card); |
1208 | cancel_delayed_work_sync(&card->buffer_reclaim_work); | 1232 | cancel_delayed_work_sync(&card->buffer_reclaim_work); |
1209 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) | 1233 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) |
1210 | kfree_skb(card->qdio.in_q->bufs[j].rx_skb); | 1234 | dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb); |
1211 | kfree(card->qdio.in_q); | 1235 | kfree(card->qdio.in_q); |
1212 | card->qdio.in_q = NULL; | 1236 | card->qdio.in_q = NULL; |
1213 | /* inbound buffer pool */ | 1237 | /* inbound buffer pool */ |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 8eff8f709866..9648e4e68337 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -3544,6 +3544,11 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev, | |||
3544 | card->info.hwtrap = 1; | 3544 | card->info.hwtrap = 1; |
3545 | } | 3545 | } |
3546 | qeth_l3_stop_card(card, recovery_mode); | 3546 | qeth_l3_stop_card(card, recovery_mode); |
3547 | if ((card->options.cq == QETH_CQ_ENABLED) && card->dev) { | ||
3548 | rtnl_lock(); | ||
3549 | call_netdevice_notifiers(NETDEV_REBOOT, card->dev); | ||
3550 | rtnl_unlock(); | ||
3551 | } | ||
3547 | rc = ccw_device_set_offline(CARD_DDEV(card)); | 3552 | rc = ccw_device_set_offline(CARD_DDEV(card)); |
3548 | rc2 = ccw_device_set_offline(CARD_WDEV(card)); | 3553 | rc2 = ccw_device_set_offline(CARD_WDEV(card)); |
3549 | rc3 = ccw_device_set_offline(CARD_RDEV(card)); | 3554 | rc3 = ccw_device_set_offline(CARD_RDEV(card)); |