Sophie

Sophie

distrib > CentOS > 5 > x86_64 > by-pkgid > ea32411352494358b8d75a78402a4713 > files > 4040

kernel-2.6.18-238.19.1.el5.centos.plus.src.rpm

From: Hendrik Brueckner <brueckner@redhat.com>
Date: Wed, 4 Aug 2010 10:02:57 -0400
Subject: [s390] qeth: avoid loop if ipa command response missing
Message-id: <1280916181-27024-5-git-send-email-brueckner@redhat.com>
Patchwork-id: 27374
O-Subject: [RHEL5.6 PATCH 4/8] [s390x] qeth: avoid loop if ipa command response
	is missing
Bugzilla: 619451
RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com>

Description
-----------
endless loop in qeth_send_control_data

If qeth issues an ipa command, but for some reasons the
response never comes back, qeth reaches a timeout. In this
case the irq_pending flag of the write channel is not reset,
and the command buffer is not reinitialized.

Reset the irq_pending flag of the write channel in timeout
handling code, clear the command buffer, clear the list of
scheduled ipa commands and trigger a recovery. This avoids
endless looping in case of ipa command timeout.

Bugzilla
--------
BZ 619451
https://bugzilla.redhat.com/show_bug.cgi?id=619451

Upstream status of the patch
----------------------------
http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=908abbb5773213288c8ed033c3313440b31cfbf3

Test status
-----------
The patch has been tested and fixes the problem.
The fix has been verified by the IBM test department.

diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index 1fb19f6..ca7f10f 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -852,6 +852,7 @@ struct qeth_card {
 	struct qeth_osn_info osn_info;
 	atomic_t force_alloc_skb;
 	struct service_level qeth_service_level;
+	int read_or_write_problem;
 };
 
 struct qeth_card_list_struct {
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 8513ef8..1344cac 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -1075,6 +1075,7 @@ qeth_setup_card(struct qeth_card *card)
 	card->state = CARD_STATE_DOWN;
 	card->lan_online = 0;
 	card->use_hard_stop = 0;
+	card->read_or_write_problem = 0;
 	card->dev = NULL;
 #ifdef CONFIG_QETH_VLAN
 	spin_lock_init(&card->vlanlock);
@@ -1659,6 +1660,7 @@ qeth_issue_next_read(struct qeth_card *card)
 	if (rc) {
 		PRINT_ERR("Error in starting next read ccw! rc=%i\n", rc);
 		atomic_set(&card->read.irq_pending, 0);
+		card->read_or_write_problem = 1;
 		qeth_schedule_recovery(card);
 		wake_up(&card->wait_q);
 	}
@@ -1881,6 +1883,10 @@ qeth_send_control_data(struct qeth_card *card, int len,
 
 	QETH_DBF_TEXT(trace, 2, "sendctl");
 
+	if (card->read_or_write_problem) {
+		qeth_release_buffer(iob->channel, iob);
+		return -EIO;
+	}
 	reply = qeth_alloc_reply(card);
 	if (!reply) {
 		PRINT_WARN("Could no alloc qeth_reply!\n");
@@ -1931,6 +1937,10 @@ qeth_send_control_data(struct qeth_card *card, int len,
 			spin_unlock_irqrestore(&reply->card->lock, flags);
 			reply->rc = -ETIME;
 			atomic_inc(&reply->received);
+			atomic_set(&card->write.irq_pending, 0);
+			qeth_release_buffer(iob->channel, iob);
+			card->write.buf_no = (card->write.buf_no + 1) %
+							QETH_CMD_BUFFER_NO;
 			wake_up(&reply->wait_q);
 		}
 	};
@@ -2016,6 +2026,10 @@ qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
 	qeth_prepare_ipa_cmd(card,iob,prot_type);
 	rc = qeth_send_control_data(card, IPA_CMD_LENGTH, iob,
 				    reply_cb, reply_param);
+	if (rc == -ETIME) {
+		card->read_or_write_problem = 1;
+		qeth_schedule_recovery(card);
+	}
 	return rc;
 }
 
@@ -6776,6 +6790,7 @@ retry:
 		else
 			goto retry;
 	}
+	card->read_or_write_problem = 0;
 	if ((rc = qeth_mpc_initialize(card))){
 		QETH_DBF_TEXT_(setup, 2, "5err%d", rc);
 		goto out;