aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device_fsm.c
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/cio/device_fsm.c
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/cio/device_fsm.c')
-rw-r--r--drivers/s390/cio/device_fsm.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 4395c01a9dac..a845695ac314 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);