diff options
author | Ursula Braun <braunu@de.ibm.com> | 2008-07-14 03:57:25 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-14 04:01:59 -0400 |
commit | bb0ca330a7e273cdecebae0283c9d267f60fe363 (patch) | |
tree | d5d1c3fb50c9ef53dedf5cafcd69b7b0214176be /drivers/s390/cio/qdio.c | |
parent | b1c02d9110e72ec510ec9b038f9564e3c0d87384 (diff) |
[S390] qdio: Repair timeout handling for qdio_shutdown
If qdio shutdown runs in parallel with a channel error,
the qdio_timeout_handler might not be triggered.
In this case neither state INACTIVE nor state ERR
is reached and the following wait_event hangs forever.
Solution: do not make use of ccw_device_set_timeout(),
but add a timeout to the following wait_event.
And make sure, wake_up is called in case of an
i/o error on the qdio-device.
Signed-off-by: Ursula Braun <braunu@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/qdio.c')
-rw-r--r-- | drivers/s390/cio/qdio.c | 20 |
1 files changed, 7 insertions, 13 deletions
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 445cf364e461..17df222dea80 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
@@ -2082,7 +2082,6 @@ qdio_timeout_handler(struct ccw_device *cdev) | |||
2082 | default: | 2082 | default: |
2083 | BUG(); | 2083 | BUG(); |
2084 | } | 2084 | } |
2085 | ccw_device_set_timeout(cdev, 0); | ||
2086 | wake_up(&cdev->private->wait_q); | 2085 | wake_up(&cdev->private->wait_q); |
2087 | } | 2086 | } |
2088 | 2087 | ||
@@ -2121,6 +2120,8 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
2121 | case -EIO: | 2120 | case -EIO: |
2122 | QDIO_PRINT_ERR("i/o error on device %s\n", | 2121 | QDIO_PRINT_ERR("i/o error on device %s\n", |
2123 | cdev->dev.bus_id); | 2122 | cdev->dev.bus_id); |
2123 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); | ||
2124 | wake_up(&cdev->private->wait_q); | ||
2124 | return; | 2125 | return; |
2125 | case -ETIMEDOUT: | 2126 | case -ETIMEDOUT: |
2126 | qdio_timeout_handler(cdev); | 2127 | qdio_timeout_handler(cdev); |
@@ -2667,12 +2668,12 @@ qdio_shutdown(struct ccw_device *cdev, int how) | |||
2667 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); | 2668 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); |
2668 | } else if (rc == 0) { | 2669 | } else if (rc == 0) { |
2669 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP); | 2670 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP); |
2670 | ccw_device_set_timeout(cdev, timeout); | ||
2671 | spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags); | 2671 | spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags); |
2672 | 2672 | ||
2673 | wait_event(cdev->private->wait_q, | 2673 | wait_event_interruptible_timeout(cdev->private->wait_q, |
2674 | irq_ptr->state == QDIO_IRQ_STATE_INACTIVE || | 2674 | irq_ptr->state == QDIO_IRQ_STATE_INACTIVE || |
2675 | irq_ptr->state == QDIO_IRQ_STATE_ERR); | 2675 | irq_ptr->state == QDIO_IRQ_STATE_ERR, |
2676 | timeout); | ||
2676 | } else { | 2677 | } else { |
2677 | QDIO_PRINT_INFO("ccw_device_{halt,clear} returned %d for " | 2678 | QDIO_PRINT_INFO("ccw_device_{halt,clear} returned %d for " |
2678 | "device %s\n", result, cdev->dev.bus_id); | 2679 | "device %s\n", result, cdev->dev.bus_id); |
@@ -2692,7 +2693,6 @@ qdio_shutdown(struct ccw_device *cdev, int how) | |||
2692 | 2693 | ||
2693 | /* Ignore errors. */ | 2694 | /* Ignore errors. */ |
2694 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); | 2695 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); |
2695 | ccw_device_set_timeout(cdev, 0); | ||
2696 | out: | 2696 | out: |
2697 | up(&irq_ptr->setting_up_sema); | 2697 | up(&irq_ptr->setting_up_sema); |
2698 | return result; | 2698 | return result; |
@@ -2907,13 +2907,10 @@ qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat) | |||
2907 | QDIO_DBF_TEXT0(0,setup,dbf_text); | 2907 | QDIO_DBF_TEXT0(0,setup,dbf_text); |
2908 | QDIO_DBF_TEXT0(0,trace,dbf_text); | 2908 | QDIO_DBF_TEXT0(0,trace,dbf_text); |
2909 | 2909 | ||
2910 | if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat)) { | 2910 | if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat)) |
2911 | ccw_device_set_timeout(cdev, 0); | ||
2912 | return; | 2911 | return; |
2913 | } | ||
2914 | 2912 | ||
2915 | qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED); | 2913 | qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED); |
2916 | ccw_device_set_timeout(cdev, 0); | ||
2917 | } | 2914 | } |
2918 | 2915 | ||
2919 | int | 2916 | int |
@@ -3196,8 +3193,6 @@ qdio_establish(struct qdio_initialize *init_data) | |||
3196 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no, | 3193 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no, |
3197 | result, result2); | 3194 | result, result2); |
3198 | result=result2; | 3195 | result=result2; |
3199 | if (result) | ||
3200 | ccw_device_set_timeout(cdev, 0); | ||
3201 | } | 3196 | } |
3202 | 3197 | ||
3203 | spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags); | 3198 | spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags); |
@@ -3279,7 +3274,6 @@ qdio_activate(struct ccw_device *cdev, int flags) | |||
3279 | 3274 | ||
3280 | spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags); | 3275 | spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags); |
3281 | 3276 | ||
3282 | ccw_device_set_timeout(cdev, 0); | ||
3283 | ccw_device_set_options(cdev, CCWDEV_REPORT_ALL); | 3277 | ccw_device_set_options(cdev, CCWDEV_REPORT_ALL); |
3284 | result=ccw_device_start(cdev,&irq_ptr->ccw,QDIO_DOING_ACTIVATE, | 3278 | result=ccw_device_start(cdev,&irq_ptr->ccw,QDIO_DOING_ACTIVATE, |
3285 | 0, DOIO_DENY_PREFETCH); | 3279 | 0, DOIO_DENY_PREFETCH); |