diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2006-12-04 09:41:04 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2006-12-04 09:41:04 -0500 |
commit | d23861ff1a4da1f4a5255eb4582f620191c6e1c0 (patch) | |
tree | fcf5cd0ce14600f2ace203bc71ae940db7fe6497 /drivers/s390/cio/chsc.c | |
parent | 24cb5b4846ebae5543869b5c596c2650f380df53 (diff) |
[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.c | 37 |
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) | |||
251 | cc = cio_clear(sch); | 251 | cc = cio_clear(sch); |
252 | if (cc == -ENODEV) | 252 | if (cc == -ENODEV) |
253 | goto out_unreg; | 253 | goto out_unreg; |
254 | /* Request retry of internal operation. */ | ||
255 | device_set_intretry(sch); | ||
254 | /* Call handler. */ | 256 | /* Call handler. */ |
255 | if (sch->driver && sch->driver->termination) | 257 | if (sch->driver && sch->driver->termination) |
256 | sch->driver->termination(&sch->dev); | 258 | sch->driver->termination(&sch->dev); |
@@ -711,9 +713,6 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index) | |||
711 | { | 713 | { |
712 | int cc; | 714 | int cc; |
713 | 715 | ||
714 | if (!device_is_online(sch)) | ||
715 | /* cio could be doing I/O. */ | ||
716 | return 0; | ||
717 | cc = stsch(sch->schid, &sch->schib); | 716 | cc = stsch(sch->schid, &sch->schib); |
718 | if (cc) | 717 | if (cc) |
719 | return 0; | 718 | return 0; |
@@ -722,6 +721,26 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index) | |||
722 | return 0; | 721 | return 0; |
723 | } | 722 | } |
724 | 723 | ||
724 | static void terminate_internal_io(struct subchannel *sch) | ||
725 | { | ||
726 | if (cio_clear(sch)) { | ||
727 | /* Recheck device in case clear failed. */ | ||
728 | sch->lpm = 0; | ||
729 | if (device_trigger_verify(sch) != 0) { | ||
730 | if(css_enqueue_subchannel_slow(sch->schid)) { | ||
731 | css_clear_subchannel_slow_list(); | ||
732 | need_rescan = 1; | ||
733 | } | ||
734 | } | ||
735 | return; | ||
736 | } | ||
737 | /* Request retry of internal operation. */ | ||
738 | device_set_intretry(sch); | ||
739 | /* Call handler. */ | ||
740 | if (sch->driver && sch->driver->termination) | ||
741 | sch->driver->termination(&sch->dev); | ||
742 | } | ||
743 | |||
725 | static inline void | 744 | static inline void |
726 | __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) | 745 | __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) |
727 | { | 746 | { |
@@ -748,10 +767,14 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) | |||
748 | } | 767 | } |
749 | sch->opm &= ~(0x80 >> chp); | 768 | sch->opm &= ~(0x80 >> chp); |
750 | sch->lpm &= ~(0x80 >> chp); | 769 | sch->lpm &= ~(0x80 >> chp); |
751 | if (check_for_io_on_path(sch, chp)) | 770 | if (check_for_io_on_path(sch, chp)) { |
752 | /* Path verification is done after killing. */ | 771 | if (device_is_online(sch)) |
753 | device_kill_io(sch); | 772 | /* Path verification is done after killing. */ |
754 | else if (!sch->lpm) { | 773 | device_kill_io(sch); |
774 | else | ||
775 | /* Kill and retry internal I/O. */ | ||
776 | terminate_internal_io(sch); | ||
777 | } else if (!sch->lpm) { | ||
755 | if (device_trigger_verify(sch) != 0) { | 778 | if (device_trigger_verify(sch) != 0) { |
756 | if (css_enqueue_subchannel_slow(sch->schid)) { | 779 | if (css_enqueue_subchannel_slow(sch->schid)) { |
757 | css_clear_subchannel_slow_list(); | 780 | css_clear_subchannel_slow_list(); |