Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Einar Lueck and committed by
David S. Miller
72861ae7 3f36b890

+34 -5
+29 -5
drivers/s390/net/qeth_core_main.c
··· 66 66 static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, 67 67 struct qeth_qdio_out_buffer *buf, 68 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 71 static inline const char *qeth_get_cardname(struct qeth_card *card) 72 72 { ··· 363 363 static inline void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, 364 364 int bidx, int forced_cleanup) 365 365 { 366 + if (q->card->options.cq != QETH_CQ_ENABLED) 367 + return; 368 + 366 369 if (q->bufs[bidx]->next_pending != NULL) { 367 370 struct qeth_qdio_out_buffer *head = q->bufs[bidx]; 368 371 struct qeth_qdio_out_buffer *c = q->bufs[bidx]->next_pending; ··· 393 390 394 391 } 395 392 } 393 + if (forced_cleanup && (atomic_read(&(q->bufs[bidx]->state)) == 394 + QETH_QDIO_BUF_HANDLED_DELAYED)) { 395 + /* for recovery situations */ 396 + q->bufs[bidx]->aob = q->bufstates[bidx].aob; 397 + qeth_init_qdio_out_buf(q, bidx); 398 + QETH_CARD_TEXT(q->card, 2, "clprecov"); 399 + } 396 400 } 397 401 398 402 ··· 422 412 notification = TX_NOTIFY_OK; 423 413 } else { 424 414 BUG_ON(atomic_read(&buffer->state) != QETH_QDIO_BUF_PENDING); 425 - 426 415 atomic_set(&buffer->state, QETH_QDIO_BUF_IN_CQ); 427 416 notification = TX_NOTIFY_DELAYED_OK; 428 417 } ··· 434 425 435 426 buffer->aob = NULL; 436 427 qeth_clear_output_buffer(buffer->q, buffer, 437 - QETH_QDIO_BUF_HANDLED_DELAYED); 428 + QETH_QDIO_BUF_HANDLED_DELAYED); 429 + 438 430 /* from here on: do not touch buffer anymore */ 439 431 qdio_release_aob(aob); 440 432 } ··· 1123 1113 static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) 1124 1114 { 1125 1115 struct sk_buff *skb; 1116 + struct iucv_sock *iucv; 1117 + int notify_general_error = 0; 1118 + 1119 + if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING) 1120 + notify_general_error = 1; 1121 + 1122 + /* release may never happen from within CQ tasklet scope */ 1123 + BUG_ON(atomic_read(&buf->state) == QETH_QDIO_BUF_IN_CQ); 1126 1124 1127 1125 skb = skb_dequeue(&buf->skb_list); 1128 1126 while (skb) { 1129 1127 QETH_CARD_TEXT(buf->q->card, 5, "skbr"); 1130 1128 QETH_CARD_TEXT_(buf->q->card, 5, "%lx", (long) skb); 1129 + if (notify_general_error && skb->protocol == ETH_P_AF_IUCV) { 1130 + if (skb->sk) { 1131 + iucv = iucv_sk(skb->sk); 1132 + iucv->sk_txnotify(skb, TX_NOTIFY_GENERALERROR); 1133 + } 1134 + } 1131 1135 atomic_dec(&skb->users); 1132 1136 dev_kfree_skb_any(skb); 1133 1137 skb = skb_dequeue(&buf->skb_list); ··· 1184 1160 for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { 1185 1161 if (!q->bufs[j]) 1186 1162 continue; 1187 - qeth_cleanup_handled_pending(q, j, free); 1163 + qeth_cleanup_handled_pending(q, j, 1); 1188 1164 qeth_clear_output_buffer(q, q->bufs[j], QETH_QDIO_BUF_EMPTY); 1189 1165 if (free) { 1190 1166 kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[j]); ··· 1231 1207 qeth_free_cq(card); 1232 1208 cancel_delayed_work_sync(&card->buffer_reclaim_work); 1233 1209 for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) 1234 - kfree_skb(card->qdio.in_q->bufs[j].rx_skb); 1210 + dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb); 1235 1211 kfree(card->qdio.in_q); 1236 1212 card->qdio.in_q = NULL; 1237 1213 /* inbound buffer pool */
+5
drivers/s390/net/qeth_l3_main.c
··· 3544 3544 card->info.hwtrap = 1; 3545 3545 } 3546 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 3552 rc = ccw_device_set_offline(CARD_DDEV(card)); 3548 3553 rc2 = ccw_device_set_offline(CARD_WDEV(card)); 3549 3554 rc3 = ccw_device_set_offline(CARD_RDEV(card));