]>
Commit | Line | Data |
---|---|---|
82094b55 AF |
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. */ |