diff options
| -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; |
