]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.arch/s390-18-02-cio-race.patch
Fix oinkmaster patch.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.arch / s390-18-02-cio-race.patch
1 From: Gerald Schaefer <geraldsc@de.ibm.com>
2 Subject: cio: failing set online/offline processing
3 References: bnc#533267,LTC#55510
4
5 Symptom: A set online or set offline fails for a DASD device.
6 Afterwards this device can neither be set online nor offline.
7 Problem: When unit checks trigger sensing the device state is set to W4SENSE
8 until sense completion; then the device state is set back to
9 ONLINE. If a unit check occurs while set online or set offline
10 requests are processed then it might happen that the device's
11 temporary W4SENSE state causes these functions to terminate,
12 leaving the device in an inconsistent state when the state is set
13 back to ONLINE later on so that the device cannot be set online or
14 offline any longer.
15 Solution: Process set online/offline and related rollback or error routines
16 only if the device is in a final or DISCONNECTED state.
17
18 Acked-by: John Jolly <jjolly@suse.de>
19
20 Index: linux-sles11/drivers/s390/cio/device.c
21 ===================================================================
22 --- linux-sles11.orig/drivers/s390/cio/device.c 2009-08-18 13:31:25.000000000 +0200
23 +++ linux-sles11/drivers/s390/cio/device.c 2009-08-18 13:36:48.000000000 +0200
24 @@ -381,26 +381,30 @@
25 }
26 cdev->online = 0;
27 spin_lock_irq(cdev->ccwlock);
28 - ret = ccw_device_offline(cdev);
29 - if (ret == -ENODEV) {
30 - if (cdev->private->state != DEV_STATE_NOT_OPER) {
31 - cdev->private->state = DEV_STATE_OFFLINE;
32 - dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
33 - }
34 + /* Wait until a final state or DISCONNECTED is reached */
35 + while (!dev_fsm_final_state(cdev) &&
36 + cdev->private->state != DEV_STATE_DISCONNECTED) {
37 spin_unlock_irq(cdev->ccwlock);
38 - return ret;
39 + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
40 + cdev->private->state == DEV_STATE_DISCONNECTED));
41 + spin_lock_irq(cdev->ccwlock);
42 }
43 + ret = ccw_device_offline(cdev);
44 + if (ret)
45 + goto error;
46 spin_unlock_irq(cdev->ccwlock);
47 - if (ret == 0)
48 - wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
49 - else {
50 - CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
51 - "device 0.%x.%04x\n",
52 - ret, cdev->private->dev_id.ssid,
53 - cdev->private->dev_id.devno);
54 - cdev->online = 1;
55 - }
56 - return ret;
57 + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
58 + cdev->private->state == DEV_STATE_DISCONNECTED));
59 + return 0;
60 +
61 +error:
62 + CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device 0.%x.%04x\n",
63 + ret, cdev->private->dev_id.ssid,
64 + cdev->private->dev_id.devno);
65 + cdev->private->state = DEV_STATE_OFFLINE;
66 + dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
67 + spin_unlock_irq(cdev->ccwlock);
68 + return -ENODEV;
69 }
70
71 /**
72 @@ -418,6 +422,7 @@
73 int ccw_device_set_online(struct ccw_device *cdev)
74 {
75 int ret;
76 + int ret2;
77
78 if (!cdev)
79 return -ENODEV;
80 @@ -436,23 +441,47 @@
81 cdev->private->dev_id.devno);
82 return ret;
83 }
84 - if (cdev->private->state != DEV_STATE_ONLINE)
85 + spin_lock_irq(cdev->ccwlock);
86 + /* Check if online processing was successful */
87 + if ((cdev->private->state != DEV_STATE_ONLINE) &&
88 + (cdev->private->state != DEV_STATE_W4SENSE)) {
89 + spin_unlock_irq(cdev->ccwlock);
90 return -ENODEV;
91 - if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) {
92 - cdev->online = 1;
93 - return 0;
94 }
95 + spin_unlock_irq(cdev->ccwlock);
96 + if (cdev->drv->set_online)
97 + ret = cdev->drv->set_online(cdev);
98 + if (ret)
99 + goto rollback;
100 + cdev->online = 1;
101 + return 0;
102 +
103 +rollback:
104 spin_lock_irq(cdev->ccwlock);
105 - ret = ccw_device_offline(cdev);
106 + /* Wait until a final state or DISCONNECTED is reached */
107 + while (!dev_fsm_final_state(cdev) &&
108 + cdev->private->state != DEV_STATE_DISCONNECTED) {
109 + spin_unlock_irq(cdev->ccwlock);
110 + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
111 + cdev->private->state == DEV_STATE_DISCONNECTED));
112 + spin_lock_irq(cdev->ccwlock);
113 + }
114 + ret2 = ccw_device_offline(cdev);
115 + if (ret2)
116 + goto error;
117 spin_unlock_irq(cdev->ccwlock);
118 - if (ret == 0)
119 - wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
120 - else
121 - CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
122 - "device 0.%x.%04x\n",
123 - ret, cdev->private->dev_id.ssid,
124 - cdev->private->dev_id.devno);
125 - return (ret == 0) ? -ENODEV : ret;
126 + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
127 + cdev->private->state == DEV_STATE_DISCONNECTED));
128 + return ret;
129 +
130 +error:
131 + CIO_MSG_EVENT(0, "rollback ccw_device_offline returned %d, "
132 + "device 0.%x.%04x\n",
133 + ret2, cdev->private->dev_id.ssid,
134 + cdev->private->dev_id.devno);
135 + cdev->private->state = DEV_STATE_OFFLINE;
136 + spin_unlock_irq(cdev->ccwlock);
137 + return ret;
138 }
139
140 static void online_store_handle_offline(struct ccw_device *cdev)
141 Index: linux-sles11/drivers/s390/cio/device_fsm.c
142 ===================================================================
143 --- linux-sles11.orig/drivers/s390/cio/device_fsm.c 2009-08-18 13:31:26.000000000 +0200
144 +++ linux-sles11/drivers/s390/cio/device_fsm.c 2009-08-18 13:32:47.000000000 +0200
145 @@ -903,6 +903,8 @@
146 }
147 call_handler:
148 cdev->private->state = DEV_STATE_ONLINE;
149 + /* In case sensing interfered with setting the device online */
150 + wake_up(&cdev->private->wait_q);
151 /* Call the handler. */
152 if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
153 /* Start delayed path verification. */