summaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/chsc.c
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2006-12-04 15:41:04 +0100
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2006-12-04 15:41:04 +0100
commitd23861ff1a4da1f4a5255eb4582f620191c6e1c0 (patch)
treefcf5cd0ce14600f2ace203bc71ae940db7fe6497 /drivers/s390/cio/chsc.c
parent24cb5b4846ebae5543869b5c596c2650f380df53 (diff)
downloadlinux-d23861ff1a4da1f4a5255eb4582f620191c6e1c0.tar.bz2
[S390] cio: Retry internal operations after vary off.
If I/O was running on a just varied off chpid, it will be terminated. If this was a common I/O layer internal I/O, it needs to be retried. Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/chsc.c')
-rw-r--r--drivers/s390/cio/chsc.c37
1 files changed, 30 insertions, 7 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 11900de94cb3..dbfb77b03928 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -251,6 +251,8 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
cc = cio_clear(sch);
if (cc == -ENODEV)
goto out_unreg;
+ /* Request retry of internal operation. */
+ device_set_intretry(sch);
/* Call handler. */
if (sch->driver && sch->driver->termination)
sch->driver->termination(&sch->dev);
@@ -711,9 +713,6 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index)
{
int cc;
- if (!device_is_online(sch))
- /* cio could be doing I/O. */
- return 0;
cc = stsch(sch->schid, &sch->schib);
if (cc)
return 0;
@@ -722,6 +721,26 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index)
return 0;
}
+static void terminate_internal_io(struct subchannel *sch)
+{
+ if (cio_clear(sch)) {
+ /* Recheck device in case clear failed. */
+ sch->lpm = 0;
+ if (device_trigger_verify(sch) != 0) {
+ if(css_enqueue_subchannel_slow(sch->schid)) {
+ css_clear_subchannel_slow_list();
+ need_rescan = 1;
+ }
+ }
+ return;
+ }
+ /* Request retry of internal operation. */
+ device_set_intretry(sch);
+ /* Call handler. */
+ if (sch->driver && sch->driver->termination)
+ sch->driver->termination(&sch->dev);
+}
+
static inline void
__s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
{
@@ -748,10 +767,14 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
}
sch->opm &= ~(0x80 >> chp);
sch->lpm &= ~(0x80 >> chp);
- if (check_for_io_on_path(sch, chp))
- /* Path verification is done after killing. */
- device_kill_io(sch);
- else if (!sch->lpm) {
+ if (check_for_io_on_path(sch, chp)) {
+ if (device_is_online(sch))
+ /* Path verification is done after killing. */
+ device_kill_io(sch);
+ else
+ /* Kill and retry internal I/O. */
+ terminate_internal_io(sch);
+ } else if (!sch->lpm) {
if (device_trigger_verify(sch) != 0) {
if (css_enqueue_subchannel_slow(sch->schid)) {
css_clear_subchannel_slow_list();