aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorEinar Lueck <elelueck@de.ibm.com>2011-12-19 17:56:36 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-20 14:05:04 -0500
commit72861ae792c2263bd1058dd3b034e0bf84a676c1 (patch)
treeebc71e3c899f075d5257722efcb26c58703b2c3e /drivers/s390
parent3f36b890dea7c2fc2fe25fb507552a46a226048a (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.c34
-rw-r--r--drivers/s390/net/qeth_l3_main.c5
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);
66static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, 66static 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 69static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
70 70
71static inline const char *qeth_get_cardname(struct qeth_card *card) 71static 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,
363static inline void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, 363static 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:
1113static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) 1123static 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));