From 376ae4752e3a387d41a2ba9c9ea45c2df625e6e4 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 25 Oct 2010 16:10:44 +0200 Subject: [PATCH] [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 Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 1 + drivers/s390/cio/device_fsm.c | 9 +++++++-- 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) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO)); while (ret == -EBUSY) { cdev->private->state = DEV_STATE_QUIESCE; + cdev->private->iretry = 255; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { 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) ret = cio_clear (sch); return (ret == 0) ? -EBUSY : ret; } - panic("Can't stop i/o on subchannel.\n"); + /* Function was unsuccessful */ + CIO_MSG_EVENT(0, "0.%x.%04x: could not stop I/O\n", + cdev->private->dev_id.ssid, cdev->private->dev_id.devno); + return -EIO; } void 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) int ret; ccw_device_set_timeout(cdev, 0); + cdev->private->iretry = 255; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); cdev->private->state = DEV_STATE_TIMEOUT_KILL; return; } - if (ret == -ENODEV) + if (ret) dev_fsm_event(cdev, DEV_EVENT_NOTOPER); else if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, @@ -869,6 +873,7 @@ void ccw_device_kill_io(struct ccw_device *cdev) { int ret; + cdev->private->iretry = 255; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); -- 2.20.1