Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3093

kernel-2.6.18-194.11.1.el5.src.rpm

From: Hans-Joachim Picht <hpicht@redhat.com>
Date: Fri, 27 Feb 2009 19:54:49 +0100
Subject: [s390] cio: Properly disable not operational subchannel
Message-id: 20090227185449.GA2447@redhat.com
O-Subject: [RHEL5 U4 PATCH 1/1] - cio: Properly disable not operational subchannel.
Bugzilla: 487701
RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com>

Description
============

We might run into the following a Kernel BUG at
drivers/s390/cio/device_fsm.c:1241!

Problem:  After deferred cc=3 was received on all paths, a
device was set to not operational to prepare for
re-evaluation. An unsolicited interrupt indicating
that the device became accessible again triggered
an invalid event in the state machine (interrupt in
not operational state).
Solution:    Properly disable the subchannel before setting the
device not operational. To be able to disable the
subchannel reliably, pending status needs to be
collected.

Bugzilla
=========

BZ 487701
https://bugzilla.redhat.com/show_bug.cgi?id=487701

Upstream status of the patch:
=============================
The patch has been posted upstream

http://marc.info/?l=linux-s390&m=123557461717201&w=2

This posting is a a port of all the s390 patches we would like to
integrate into linux-2.6 once the 2.6.30 merge window opens.

Test status:
============

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

Please ACK.

With best regards,

	--Hans

diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index acb393d..a6df5e4 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -466,25 +466,16 @@ cio_disable_subchannel (struct subchannel *sch)
 	if (ccode == 3)		/* Not operational. */
 		return -ENODEV;
 
-	if (sch->schib.scsw.actl != 0)
-		/*
-		 * the disable function must not be called while there are
-		 *  requests pending for completion !
-		 */
-		return -EBUSY;
-
 	for (retry = 5, ret = 0; retry > 0; retry--) {
 		sch->schib.pmcw.ena = 0;
 		ret = cio_modify(sch);
 		if (ret == -ENODEV)
 			break;
-		if (ret == -EBUSY)
-			/*
-			 * The subchannel is busy or status pending.
-			 * We'll disable when the next interrupt was delivered
-			 * via the state machine.
-			 */
-			break;
+		if (ret == -EBUSY) {
+			struct irb irb;
+			if (tsch(sch->schid, &irb) != 0)
+				break;
+		}
 		if (ret == 0) {
 			stsch (sch->schid, &sch->schib);
 			if (!sch->schib.pmcw.ena)
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 162154f..7a9bac0 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -802,8 +802,10 @@ static void ccw_device_generic_notoper(struct ccw_device *cdev,
 {
 	struct subchannel *sch;
 
-	cdev->private->state = DEV_STATE_NOT_OPER;
 	sch = to_subchannel(cdev->dev.parent);
+	ccw_device_set_timeout(cdev, 0);
+	cio_disable_subchannel(sch);
+	cdev->private->state = DEV_STATE_NOT_OPER;
 	css_schedule_eval(sch->schid);
 }
 
@@ -1169,7 +1171,7 @@ ccw_device_offline_irq(struct ccw_device *cdev, enum dev_event dev_event)
 	sch = to_subchannel(cdev->dev.parent);
 	/*
 	 * An interrupt in state offline means a previous disable was not
-	 * successful. Try again.
+	 * successful - should not happen, but we try to disable again.
 	 */
 	cio_disable_subchannel(sch);
 }