diff options
Diffstat (limited to 'drivers/s390/cio/cio.c')
-rw-r--r-- | drivers/s390/cio/cio.c | 79 |
1 files changed, 43 insertions, 36 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 396bada65f86..3eb6cb608fc9 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -691,7 +691,22 @@ wait_cons_dev (void) | |||
691 | } | 691 | } |
692 | 692 | ||
693 | static int | 693 | static int |
694 | cio_console_irq(void) | 694 | cio_test_for_console(struct subchannel_id schid, void *data) |
695 | { | ||
696 | if (stsch(schid, &console_subchannel.schib) != 0) | ||
697 | return -ENXIO; | ||
698 | if (console_subchannel.schib.pmcw.dnv && | ||
699 | console_subchannel.schib.pmcw.dev == | ||
700 | console_devno) { | ||
701 | console_irq = schid.sch_no; | ||
702 | return 1; /* found */ | ||
703 | } | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | |||
708 | static int | ||
709 | cio_get_console_sch_no(void) | ||
695 | { | 710 | { |
696 | struct subchannel_id schid; | 711 | struct subchannel_id schid; |
697 | 712 | ||
@@ -705,16 +720,7 @@ cio_console_irq(void) | |||
705 | console_devno = console_subchannel.schib.pmcw.dev; | 720 | console_devno = console_subchannel.schib.pmcw.dev; |
706 | } else if (console_devno != -1) { | 721 | } else if (console_devno != -1) { |
707 | /* At least the console device number is known. */ | 722 | /* At least the console device number is known. */ |
708 | do { | 723 | for_each_subchannel(cio_test_for_console, NULL); |
709 | if (stsch(schid, &console_subchannel.schib) != 0) | ||
710 | break; | ||
711 | if (console_subchannel.schib.pmcw.dnv && | ||
712 | console_subchannel.schib.pmcw.dev == | ||
713 | console_devno) { | ||
714 | console_irq = schid.sch_no; | ||
715 | break; | ||
716 | } | ||
717 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); | ||
718 | if (console_irq == -1) | 724 | if (console_irq == -1) |
719 | return -1; | 725 | return -1; |
720 | } else { | 726 | } else { |
@@ -730,19 +736,19 @@ cio_console_irq(void) | |||
730 | struct subchannel * | 736 | struct subchannel * |
731 | cio_probe_console(void) | 737 | cio_probe_console(void) |
732 | { | 738 | { |
733 | int irq, ret; | 739 | int sch_no, ret; |
734 | struct subchannel_id schid; | 740 | struct subchannel_id schid; |
735 | 741 | ||
736 | if (xchg(&console_subchannel_in_use, 1) != 0) | 742 | if (xchg(&console_subchannel_in_use, 1) != 0) |
737 | return ERR_PTR(-EBUSY); | 743 | return ERR_PTR(-EBUSY); |
738 | irq = cio_console_irq(); | 744 | sch_no = cio_get_console_sch_no(); |
739 | if (irq == -1) { | 745 | if (sch_no == -1) { |
740 | console_subchannel_in_use = 0; | 746 | console_subchannel_in_use = 0; |
741 | return ERR_PTR(-ENODEV); | 747 | return ERR_PTR(-ENODEV); |
742 | } | 748 | } |
743 | memset(&console_subchannel, 0, sizeof(struct subchannel)); | 749 | memset(&console_subchannel, 0, sizeof(struct subchannel)); |
744 | init_subchannel_id(&schid); | 750 | init_subchannel_id(&schid); |
745 | schid.sch_no = irq; | 751 | schid.sch_no = sch_no; |
746 | ret = cio_validate_subchannel(&console_subchannel, schid); | 752 | ret = cio_validate_subchannel(&console_subchannel, schid); |
747 | if (ret) { | 753 | if (ret) { |
748 | console_subchannel_in_use = 0; | 754 | console_subchannel_in_use = 0; |
@@ -830,32 +836,33 @@ __clear_subchannel_easy(struct subchannel_id schid) | |||
830 | } | 836 | } |
831 | 837 | ||
832 | extern void do_reipl(unsigned long devno); | 838 | extern void do_reipl(unsigned long devno); |
839 | static int | ||
840 | __shutdown_subchannel_easy(struct subchannel_id schid, void *data) | ||
841 | { | ||
842 | struct schib schib; | ||
843 | |||
844 | if (stsch(schid, &schib)) | ||
845 | return -ENXIO; | ||
846 | if (!schib.pmcw.ena) | ||
847 | return 0; | ||
848 | switch(__disable_subchannel_easy(schid, &schib)) { | ||
849 | case 0: | ||
850 | case -ENODEV: | ||
851 | break; | ||
852 | default: /* -EBUSY */ | ||
853 | if (__clear_subchannel_easy(schid)) | ||
854 | break; /* give up... */ | ||
855 | stsch(schid, &schib); | ||
856 | __disable_subchannel_easy(schid, &schib); | ||
857 | } | ||
858 | return 0; | ||
859 | } | ||
833 | 860 | ||
834 | /* Clear all subchannels. */ | ||
835 | void | 861 | void |
836 | clear_all_subchannels(void) | 862 | clear_all_subchannels(void) |
837 | { | 863 | { |
838 | struct subchannel_id schid; | ||
839 | |||
840 | local_irq_disable(); | 864 | local_irq_disable(); |
841 | init_subchannel_id(&schid); | 865 | for_each_subchannel(__shutdown_subchannel_easy, NULL); |
842 | do { | ||
843 | struct schib schib; | ||
844 | if (stsch(schid, &schib)) | ||
845 | break; /* break out of the loop */ | ||
846 | if (!schib.pmcw.ena) | ||
847 | continue; | ||
848 | switch(__disable_subchannel_easy(schid, &schib)) { | ||
849 | case 0: | ||
850 | case -ENODEV: | ||
851 | break; | ||
852 | default: /* -EBUSY */ | ||
853 | if (__clear_subchannel_easy(schid)) | ||
854 | break; /* give up... jump out of switch */ | ||
855 | stsch(schid, &schib); | ||
856 | __disable_subchannel_easy(schid, &schib); | ||
857 | } | ||
858 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); | ||
859 | } | 866 | } |
860 | 867 | ||
861 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | 868 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ |