diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/cio.c | 50 |
1 files changed, 40 insertions, 10 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 89320c1ad825..050963f15802 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -841,14 +841,26 @@ __clear_subchannel_easy(struct subchannel_id schid) | |||
841 | return -EBUSY; | 841 | return -EBUSY; |
842 | } | 842 | } |
843 | 843 | ||
844 | extern void do_reipl(unsigned long devno); | 844 | struct sch_match_id { |
845 | static int | 845 | struct subchannel_id schid; |
846 | __shutdown_subchannel_easy(struct subchannel_id schid, void *data) | 846 | struct ccw_dev_id devid; |
847 | int rc; | ||
848 | }; | ||
849 | |||
850 | static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid, | ||
851 | void *data) | ||
847 | { | 852 | { |
848 | struct schib schib; | 853 | struct schib schib; |
854 | struct sch_match_id *match_id = data; | ||
849 | 855 | ||
850 | if (stsch_err(schid, &schib)) | 856 | if (stsch_err(schid, &schib)) |
851 | return -ENXIO; | 857 | return -ENXIO; |
858 | if (match_id && schib.pmcw.dnv && | ||
859 | (schib.pmcw.dev == match_id->devid.devno) && | ||
860 | (schid.ssid == match_id->devid.ssid)) { | ||
861 | match_id->schid = schid; | ||
862 | match_id->rc = 0; | ||
863 | } | ||
852 | if (!schib.pmcw.ena) | 864 | if (!schib.pmcw.ena) |
853 | return 0; | 865 | return 0; |
854 | switch(__disable_subchannel_easy(schid, &schib)) { | 866 | switch(__disable_subchannel_easy(schid, &schib)) { |
@@ -864,18 +876,36 @@ __shutdown_subchannel_easy(struct subchannel_id schid, void *data) | |||
864 | return 0; | 876 | return 0; |
865 | } | 877 | } |
866 | 878 | ||
867 | void | 879 | static int clear_all_subchannels_and_match(struct ccw_dev_id *devid, |
868 | clear_all_subchannels(void) | 880 | struct subchannel_id *schid) |
869 | { | 881 | { |
882 | struct sch_match_id match_id; | ||
883 | |||
884 | match_id.devid = *devid; | ||
885 | match_id.rc = -ENODEV; | ||
870 | local_irq_disable(); | 886 | local_irq_disable(); |
871 | for_each_subchannel(__shutdown_subchannel_easy, NULL); | 887 | for_each_subchannel(__shutdown_subchannel_easy_and_match, &match_id); |
888 | if (match_id.rc == 0) | ||
889 | *schid = match_id.schid; | ||
890 | return match_id.rc; | ||
872 | } | 891 | } |
873 | 892 | ||
893 | |||
894 | void clear_all_subchannels(void) | ||
895 | { | ||
896 | local_irq_disable(); | ||
897 | for_each_subchannel(__shutdown_subchannel_easy_and_match, NULL); | ||
898 | } | ||
899 | |||
900 | extern void do_reipl_asm(__u32 schid); | ||
901 | |||
874 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | 902 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ |
875 | void | 903 | void reipl_ccw_dev(struct ccw_dev_id *devid) |
876 | reipl(unsigned long devno) | ||
877 | { | 904 | { |
878 | clear_all_subchannels(); | 905 | struct subchannel_id schid; |
906 | |||
907 | if (clear_all_subchannels_and_match(devid, &schid)) | ||
908 | panic("IPL Device not found\n"); | ||
879 | cio_reset_channel_paths(); | 909 | cio_reset_channel_paths(); |
880 | do_reipl(devno); | 910 | do_reipl_asm(*((__u32*)&schid)); |
881 | } | 911 | } |