]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Gerald Schaefer <geraldsc@de.ibm.com> |
2 | Subject: cio: Properly disable not operational subchannel. | |
3 | References: bnc#477666,LTC#51619 | |
4 | ||
5 | Symptom: Kernel BUG at drivers/s390/cio/device_fsm.c:1241! | |
6 | Problem: After deferred cc=3 was received on all paths, a | |
7 | device was set to not operational to prepare for | |
8 | re-evaluation. An unsolicited interrupt indicating | |
9 | that the device became accessible again triggered | |
10 | an invalid event in the state machine (interrupt in | |
11 | not operational state). | |
12 | Solution: Properly disable the subchannel before setting the | |
13 | device not operational. To be able to disable the | |
14 | subchannel reliably, pending status needs to be | |
15 | collected. | |
16 | ||
17 | Acked-by: John Jolly <jjolly@suse.de> | |
18 | ||
19 | --- | |
20 | drivers/s390/cio/cio.c | 19 +++++-------------- | |
21 | drivers/s390/cio/device_fsm.c | 4 ++-- | |
22 | 2 files changed, 7 insertions(+), 16 deletions(-) | |
23 | ||
24 | Index: linux-sles11/drivers/s390/cio/device_fsm.c | |
25 | =================================================================== | |
26 | --- linux-sles11.orig/drivers/s390/cio/device_fsm.c | |
27 | +++ linux-sles11/drivers/s390/cio/device_fsm.c | |
28 | @@ -726,7 +726,7 @@ static void ccw_device_generic_notoper(s | |
29 | { | |
30 | struct subchannel *sch; | |
31 | ||
32 | - cdev->private->state = DEV_STATE_NOT_OPER; | |
33 | + ccw_device_set_notoper(cdev); | |
34 | sch = to_subchannel(cdev->dev.parent); | |
35 | css_schedule_eval(sch->schid); | |
36 | } | |
37 | @@ -1048,7 +1048,7 @@ ccw_device_offline_irq(struct ccw_device | |
38 | sch = to_subchannel(cdev->dev.parent); | |
39 | /* | |
40 | * An interrupt in state offline means a previous disable was not | |
41 | - * successful. Try again. | |
42 | + * successful - should not happen, but we try to disable again. | |
43 | */ | |
44 | cio_disable_subchannel(sch); | |
45 | } | |
46 | Index: linux-sles11/drivers/s390/cio/cio.c | |
47 | =================================================================== | |
48 | --- linux-sles11.orig/drivers/s390/cio/cio.c | |
49 | +++ linux-sles11/drivers/s390/cio/cio.c | |
50 | @@ -464,25 +464,16 @@ int cio_disable_subchannel(struct subcha | |
51 | if (ccode == 3) /* Not operational. */ | |
52 | return -ENODEV; | |
53 | ||
54 | - if (scsw_actl(&sch->schib.scsw) != 0) | |
55 | - /* | |
56 | - * the disable function must not be called while there are | |
57 | - * requests pending for completion ! | |
58 | - */ | |
59 | - return -EBUSY; | |
60 | - | |
61 | for (retry = 5, ret = 0; retry > 0; retry--) { | |
62 | sch->schib.pmcw.ena = 0; | |
63 | ret = cio_modify(sch); | |
64 | if (ret == -ENODEV) | |
65 | break; | |
66 | - if (ret == -EBUSY) | |
67 | - /* | |
68 | - * The subchannel is busy or status pending. | |
69 | - * We'll disable when the next interrupt was delivered | |
70 | - * via the state machine. | |
71 | - */ | |
72 | - break; | |
73 | + if (ret == -EBUSY) { | |
74 | + struct irb irb; | |
75 | + if (tsch(sch->schid, &irb) != 0) | |
76 | + break; | |
77 | + } | |
78 | if (ret == 0) { | |
79 | stsch (sch->schid, &sch->schib); | |
80 | if (!sch->schib.pmcw.ena) |