aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2010-10-25 10:10:44 -0400
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-10-25 10:10:20 -0400
commit376ae4752e3a387d41a2ba9c9ea45c2df625e6e4 (patch)
treede54c8315a5a5c2149131e22fac3daf6291ef9fa /drivers/s390
parentc9af3fa9e1e3e5154649991a14b74f3a2dee19ee (diff)
[S390] cio: fix I/O cancel function
Function ccw_device_cancel_halt_clear may cause an unexpected kernel panic if a clear function is currently active at the subchannel for which it is called. In that case, the iretry counter used to determine the number of retries is never initialized, leading to an immediate failure of the function which results in a kernel panic. Fix this by initializing the iretry counter when the function is first called. Also replace the kernel panic with a return code: a single malfunctioning I/O device should not automatically cause a system-wide kernel panic. Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/device.c1
-rw-r--r--drivers/s390/cio/device_fsm.c9
2 files changed, 8 insertions, 2 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 881bdfd9914..2ff8a22d425 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1205,6 +1205,7 @@ static void io_subchannel_quiesce(struct subchannel *sch)
1205 cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO)); 1205 cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO));
1206 while (ret == -EBUSY) { 1206 while (ret == -EBUSY) {
1207 cdev->private->state = DEV_STATE_QUIESCE; 1207 cdev->private->state = DEV_STATE_QUIESCE;
1208 cdev->private->iretry = 255;
1208 ret = ccw_device_cancel_halt_clear(cdev); 1209 ret = ccw_device_cancel_halt_clear(cdev);
1209 if (ret == -EBUSY) { 1210 if (ret == -EBUSY) {
1210 ccw_device_set_timeout(cdev, HZ/10); 1211 ccw_device_set_timeout(cdev, HZ/10);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 4395c01a9da..a845695ac31 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -174,7 +174,10 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
174 ret = cio_clear (sch); 174 ret = cio_clear (sch);
175 return (ret == 0) ? -EBUSY : ret; 175 return (ret == 0) ? -EBUSY : ret;
176 } 176 }
177 panic("Can't stop i/o on subchannel.\n"); 177 /* Function was unsuccessful */
178 CIO_MSG_EVENT(0, "0.%x.%04x: could not stop I/O\n",
179 cdev->private->dev_id.ssid, cdev->private->dev_id.devno);
180 return -EIO;
178} 181}
179 182
180void ccw_device_update_sense_data(struct ccw_device *cdev) 183void ccw_device_update_sense_data(struct ccw_device *cdev)
@@ -766,13 +769,14 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
766 int ret; 769 int ret;
767 770
768 ccw_device_set_timeout(cdev, 0); 771 ccw_device_set_timeout(cdev, 0);
772 cdev->private->iretry = 255;
769 ret = ccw_device_cancel_halt_clear(cdev); 773 ret = ccw_device_cancel_halt_clear(cdev);
770 if (ret == -EBUSY) { 774 if (ret == -EBUSY) {
771 ccw_device_set_timeout(cdev, 3*HZ); 775 ccw_device_set_timeout(cdev, 3*HZ);
772 cdev->private->state = DEV_STATE_TIMEOUT_KILL; 776 cdev->private->state = DEV_STATE_TIMEOUT_KILL;
773 return; 777 return;
774 } 778 }
775 if (ret == -ENODEV) 779 if (ret)
776 dev_fsm_event(cdev, DEV_EVENT_NOTOPER); 780 dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
777 else if (cdev->handler) 781 else if (cdev->handler)
778 cdev->handler(cdev, cdev->private->intparm, 782 cdev->handler(cdev, cdev->private->intparm,
@@ -869,6 +873,7 @@ void ccw_device_kill_io(struct ccw_device *cdev)
869{ 873{
870 int ret; 874 int ret;
871 875
876 cdev->private->iretry = 255;
872 ret = ccw_device_cancel_halt_clear(cdev); 877 ret = ccw_device_cancel_halt_clear(cdev);
873 if (ret == -EBUSY) { 878 if (ret == -EBUSY) {
874 ccw_device_set_timeout(cdev, 3*HZ); 879 ccw_device_set_timeout(cdev, 3*HZ);