diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/chsc.c | 147 |
1 files changed, 55 insertions, 92 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index e7ba16a74ef7..007aaeb4f532 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -26,6 +26,25 @@ | |||
26 | 26 | ||
27 | static void *sei_page; | 27 | static void *sei_page; |
28 | 28 | ||
29 | static int chsc_error_from_response(int response) | ||
30 | { | ||
31 | switch (response) { | ||
32 | case 0x0001: | ||
33 | return 0; | ||
34 | case 0x0002: | ||
35 | case 0x0003: | ||
36 | case 0x0006: | ||
37 | case 0x0007: | ||
38 | case 0x0008: | ||
39 | case 0x000a: | ||
40 | return -EINVAL; | ||
41 | case 0x0004: | ||
42 | return -EOPNOTSUPP; | ||
43 | default: | ||
44 | return -EIO; | ||
45 | } | ||
46 | } | ||
47 | |||
29 | struct chsc_ssd_area { | 48 | struct chsc_ssd_area { |
30 | struct chsc_header request; | 49 | struct chsc_header request; |
31 | u16 :10; | 50 | u16 :10; |
@@ -75,11 +94,11 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) | |||
75 | ret = (ccode == 3) ? -ENODEV : -EBUSY; | 94 | ret = (ccode == 3) ? -ENODEV : -EBUSY; |
76 | goto out_free; | 95 | goto out_free; |
77 | } | 96 | } |
78 | if (ssd_area->response.code != 0x0001) { | 97 | ret = chsc_error_from_response(ssd_area->response.code); |
98 | if (ret != 0) { | ||
79 | CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n", | 99 | CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n", |
80 | schid.ssid, schid.sch_no, | 100 | schid.ssid, schid.sch_no, |
81 | ssd_area->response.code); | 101 | ssd_area->response.code); |
82 | ret = -EIO; | ||
83 | goto out_free; | 102 | goto out_free; |
84 | } | 103 | } |
85 | if (!ssd_area->sch_valid) { | 104 | if (!ssd_area->sch_valid) { |
@@ -717,36 +736,15 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) | |||
717 | return (ccode == 3) ? -ENODEV : -EBUSY; | 736 | return (ccode == 3) ? -ENODEV : -EBUSY; |
718 | 737 | ||
719 | switch (secm_area->response.code) { | 738 | switch (secm_area->response.code) { |
720 | case 0x0001: /* Success. */ | 739 | case 0x0102: |
721 | ret = 0; | 740 | case 0x0103: |
722 | break; | ||
723 | case 0x0003: /* Invalid block. */ | ||
724 | case 0x0007: /* Invalid format. */ | ||
725 | case 0x0008: /* Other invalid block. */ | ||
726 | CIO_CRW_EVENT(2, "Error in chsc request block!\n"); | ||
727 | ret = -EINVAL; | ||
728 | break; | ||
729 | case 0x0004: /* Command not provided in model. */ | ||
730 | CIO_CRW_EVENT(2, "Model does not provide secm\n"); | ||
731 | ret = -EOPNOTSUPP; | ||
732 | break; | ||
733 | case 0x0102: /* cub adresses incorrect */ | ||
734 | CIO_CRW_EVENT(2, "Invalid addresses in chsc request block\n"); | ||
735 | ret = -EINVAL; | ||
736 | break; | ||
737 | case 0x0103: /* key error */ | ||
738 | CIO_CRW_EVENT(2, "Access key error in secm\n"); | ||
739 | ret = -EINVAL; | 741 | ret = -EINVAL; |
740 | break; | ||
741 | case 0x0105: /* error while starting */ | ||
742 | CIO_CRW_EVENT(2, "Error while starting channel measurement\n"); | ||
743 | ret = -EIO; | ||
744 | break; | ||
745 | default: | 742 | default: |
746 | CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", | 743 | ret = chsc_error_from_response(secm_area->response.code); |
747 | secm_area->response.code); | ||
748 | ret = -EIO; | ||
749 | } | 744 | } |
745 | if (ret != 0) | ||
746 | CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n", | ||
747 | secm_area->response.code); | ||
750 | return ret; | 748 | return ret; |
751 | } | 749 | } |
752 | 750 | ||
@@ -827,27 +825,14 @@ int chsc_determine_channel_path_description(struct chp_id chpid, | |||
827 | goto out; | 825 | goto out; |
828 | } | 826 | } |
829 | 827 | ||
830 | switch (scpd_area->response.code) { | 828 | ret = chsc_error_from_response(scpd_area->response.code); |
831 | case 0x0001: /* Success. */ | 829 | if (ret == 0) |
830 | /* Success. */ | ||
832 | memcpy(desc, &scpd_area->desc, | 831 | memcpy(desc, &scpd_area->desc, |
833 | sizeof(struct channel_path_desc)); | 832 | sizeof(struct channel_path_desc)); |
834 | ret = 0; | 833 | else |
835 | break; | 834 | CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n", |
836 | case 0x0003: /* Invalid block. */ | ||
837 | case 0x0007: /* Invalid format. */ | ||
838 | case 0x0008: /* Other invalid block. */ | ||
839 | CIO_CRW_EVENT(2, "Error in chsc request block!\n"); | ||
840 | ret = -EINVAL; | ||
841 | break; | ||
842 | case 0x0004: /* Command not provided in model. */ | ||
843 | CIO_CRW_EVENT(2, "Model does not provide scpd\n"); | ||
844 | ret = -EOPNOTSUPP; | ||
845 | break; | ||
846 | default: | ||
847 | CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", | ||
848 | scpd_area->response.code); | 835 | scpd_area->response.code); |
849 | ret = -EIO; | ||
850 | } | ||
851 | out: | 836 | out: |
852 | free_page((unsigned long)scpd_area); | 837 | free_page((unsigned long)scpd_area); |
853 | return ret; | 838 | return ret; |
@@ -923,8 +908,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) | |||
923 | goto out; | 908 | goto out; |
924 | } | 909 | } |
925 | 910 | ||
926 | switch (scmc_area->response.code) { | 911 | ret = chsc_error_from_response(scmc_area->response.code); |
927 | case 0x0001: /* Success. */ | 912 | if (ret == 0) { |
913 | /* Success. */ | ||
928 | if (!scmc_area->not_valid) { | 914 | if (!scmc_area->not_valid) { |
929 | chp->cmg = scmc_area->cmg; | 915 | chp->cmg = scmc_area->cmg; |
930 | chp->shared = scmc_area->shared; | 916 | chp->shared = scmc_area->shared; |
@@ -935,22 +921,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) | |||
935 | chp->cmg = -1; | 921 | chp->cmg = -1; |
936 | chp->shared = -1; | 922 | chp->shared = -1; |
937 | } | 923 | } |
938 | ret = 0; | 924 | } else { |
939 | break; | 925 | CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n", |
940 | case 0x0003: /* Invalid block. */ | ||
941 | case 0x0007: /* Invalid format. */ | ||
942 | case 0x0008: /* Invalid bit combination. */ | ||
943 | CIO_CRW_EVENT(2, "Error in chsc request block!\n"); | ||
944 | ret = -EINVAL; | ||
945 | break; | ||
946 | case 0x0004: /* Command not provided. */ | ||
947 | CIO_CRW_EVENT(2, "Model does not provide scmc\n"); | ||
948 | ret = -EOPNOTSUPP; | ||
949 | break; | ||
950 | default: | ||
951 | CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", | ||
952 | scmc_area->response.code); | 926 | scmc_area->response.code); |
953 | ret = -EIO; | ||
954 | } | 927 | } |
955 | out: | 928 | out: |
956 | free_page((unsigned long)scmc_area); | 929 | free_page((unsigned long)scmc_area); |
@@ -1002,21 +975,17 @@ chsc_enable_facility(int operation_code) | |||
1002 | ret = (ret == 3) ? -ENODEV : -EBUSY; | 975 | ret = (ret == 3) ? -ENODEV : -EBUSY; |
1003 | goto out; | 976 | goto out; |
1004 | } | 977 | } |
978 | |||
1005 | switch (sda_area->response.code) { | 979 | switch (sda_area->response.code) { |
1006 | case 0x0001: /* everything ok */ | 980 | case 0x0101: |
1007 | ret = 0; | ||
1008 | break; | ||
1009 | case 0x0003: /* invalid request block */ | ||
1010 | case 0x0007: | ||
1011 | ret = -EINVAL; | ||
1012 | break; | ||
1013 | case 0x0004: /* command not provided */ | ||
1014 | case 0x0101: /* facility not provided */ | ||
1015 | ret = -EOPNOTSUPP; | 981 | ret = -EOPNOTSUPP; |
1016 | break; | 982 | break; |
1017 | default: /* something went wrong */ | 983 | default: |
1018 | ret = -EIO; | 984 | ret = chsc_error_from_response(sda_area->response.code); |
1019 | } | 985 | } |
986 | if (ret != 0) | ||
987 | CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n", | ||
988 | operation_code, sda_area->response.code); | ||
1020 | out: | 989 | out: |
1021 | free_page((unsigned long)sda_area); | 990 | free_page((unsigned long)sda_area); |
1022 | return ret; | 991 | return ret; |
@@ -1041,33 +1010,27 @@ chsc_determine_css_characteristics(void) | |||
1041 | } __attribute__ ((packed)) *scsc_area; | 1010 | } __attribute__ ((packed)) *scsc_area; |
1042 | 1011 | ||
1043 | scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 1012 | scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
1044 | if (!scsc_area) { | 1013 | if (!scsc_area) |
1045 | CIO_MSG_EVENT(0, "Was not able to determine available " | ||
1046 | "CHSCs due to no memory.\n"); | ||
1047 | return -ENOMEM; | 1014 | return -ENOMEM; |
1048 | } | ||
1049 | 1015 | ||
1050 | scsc_area->request.length = 0x0010; | 1016 | scsc_area->request.length = 0x0010; |
1051 | scsc_area->request.code = 0x0010; | 1017 | scsc_area->request.code = 0x0010; |
1052 | 1018 | ||
1053 | result = chsc(scsc_area); | 1019 | result = chsc(scsc_area); |
1054 | if (result) { | 1020 | if (result) { |
1055 | CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, " | 1021 | result = (result == 3) ? -ENODEV : -EBUSY; |
1056 | "cc=%i.\n", result); | ||
1057 | result = -EIO; | ||
1058 | goto exit; | 1022 | goto exit; |
1059 | } | 1023 | } |
1060 | 1024 | ||
1061 | if (scsc_area->response.code != 1) { | 1025 | result = chsc_error_from_response(scsc_area->response.code); |
1062 | CIO_MSG_EVENT(0, "Was not able to determine " | 1026 | if (result == 0) { |
1063 | "available CHSCs.\n"); | 1027 | memcpy(&css_general_characteristics, scsc_area->general_char, |
1064 | result = -EIO; | 1028 | sizeof(css_general_characteristics)); |
1065 | goto exit; | 1029 | memcpy(&css_chsc_characteristics, scsc_area->chsc_char, |
1066 | } | 1030 | sizeof(css_chsc_characteristics)); |
1067 | memcpy(&css_general_characteristics, scsc_area->general_char, | 1031 | } else |
1068 | sizeof(css_general_characteristics)); | 1032 | CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n", |
1069 | memcpy(&css_chsc_characteristics, scsc_area->chsc_char, | 1033 | scsc_area->response.code); |
1070 | sizeof(css_chsc_characteristics)); | ||
1071 | exit: | 1034 | exit: |
1072 | free_page ((unsigned long) scsc_area); | 1035 | free_page ((unsigned long) scsc_area); |
1073 | return result; | 1036 | return result; |