aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device.c
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2009-12-07 06:51:35 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2009-12-07 06:51:32 -0500
commit56e6b796fe9b99287648fc5686aae00106b37bab (patch)
treef0c75986905f3ff01ec1c801843f94923509af06 /drivers/s390/cio/device.c
parent24a1872d6411c7cce82c0888a4fbea23e993e051 (diff)
[S390] cio: fix quiesce state
DEV_STATE_QUIESCE is used to stop all IO on a busy subchannel. This patch fixes the following problems related to the QUIESCE state: * Fix a potential race condition which could occur when the resulting state was DEV_STATE_OFFLINE. * Add missing locking around cio_disable_subchannel, ccw_device_cancel_halt_clear and the cdev's handler. * Loop until we know for sure that the subchannel is disabled. Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r--drivers/s390/cio/device.c35
1 files changed, 19 insertions, 16 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e8cb99a63cc6..2b50f93b7fef 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1130,33 +1130,36 @@ static int io_subchannel_chp_event(struct subchannel *sch,
1130 return 0; 1130 return 0;
1131} 1131}
1132 1132
1133static void 1133static void io_subchannel_shutdown(struct subchannel *sch)
1134io_subchannel_shutdown(struct subchannel *sch)
1135{ 1134{
1136 struct ccw_device *cdev; 1135 struct ccw_device *cdev;
1137 int ret; 1136 int ret;
1138 1137
1138 spin_lock_irq(sch->lock);
1139 cdev = sch_get_cdev(sch); 1139 cdev = sch_get_cdev(sch);
1140
1141 if (cio_is_console(sch->schid)) 1140 if (cio_is_console(sch->schid))
1142 return; 1141 goto out_unlock;
1143 if (!sch->schib.pmcw.ena) 1142 if (!sch->schib.pmcw.ena)
1144 /* Nothing to do. */ 1143 goto out_unlock;
1145 return;
1146 ret = cio_disable_subchannel(sch); 1144 ret = cio_disable_subchannel(sch);
1147 if (ret != -EBUSY) 1145 if (ret != -EBUSY)
1148 /* Subchannel is disabled, we're done. */ 1146 goto out_unlock;
1149 return;
1150 cdev->private->state = DEV_STATE_QUIESCE;
1151 if (cdev->handler) 1147 if (cdev->handler)
1152 cdev->handler(cdev, cdev->private->intparm, 1148 cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO));
1153 ERR_PTR(-EIO)); 1149 while (ret == -EBUSY) {
1154 ret = ccw_device_cancel_halt_clear(cdev); 1150 cdev->private->state = DEV_STATE_QUIESCE;
1155 if (ret == -EBUSY) { 1151 ret = ccw_device_cancel_halt_clear(cdev);
1156 ccw_device_set_timeout(cdev, HZ/10); 1152 if (ret == -EBUSY) {
1157 wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); 1153 ccw_device_set_timeout(cdev, HZ/10);
1154 spin_unlock_irq(sch->lock);
1155 wait_event(cdev->private->wait_q,
1156 cdev->private->state != DEV_STATE_QUIESCE);
1157 spin_lock_irq(sch->lock);
1158 }
1159 ret = cio_disable_subchannel(sch);
1158 } 1160 }
1159 cio_disable_subchannel(sch); 1161out_unlock:
1162 spin_unlock_irq(sch->lock);
1160} 1163}
1161 1164
1162static int device_is_disconnected(struct ccw_device *cdev) 1165static int device_is_disconnected(struct ccw_device *cdev)