diff options
Diffstat (limited to 'net/iucv/iucv.c')
| -rw-r--r-- | net/iucv/iucv.c | 161 |
1 files changed, 122 insertions, 39 deletions
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index d7b54b5bfa69..8f57d4f4328a 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c | |||
| @@ -30,6 +30,9 @@ | |||
| 30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 31 | */ | 31 | */ |
| 32 | 32 | ||
| 33 | #define KMSG_COMPONENT "iucv" | ||
| 34 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
| 35 | |||
| 33 | #include <linux/module.h> | 36 | #include <linux/module.h> |
| 34 | #include <linux/moduleparam.h> | 37 | #include <linux/moduleparam.h> |
| 35 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
| @@ -424,8 +427,8 @@ static void iucv_declare_cpu(void *data) | |||
| 424 | err = "Paging or storage error"; | 427 | err = "Paging or storage error"; |
| 425 | break; | 428 | break; |
| 426 | } | 429 | } |
| 427 | printk(KERN_WARNING "iucv_register: iucv_declare_buffer " | 430 | pr_warning("Defining an interrupt buffer on CPU %i" |
| 428 | "on cpu %i returned error 0x%02x (%s)\n", cpu, rc, err); | 431 | " failed with 0x%02x (%s)\n", cpu, rc, err); |
| 429 | return; | 432 | return; |
| 430 | } | 433 | } |
| 431 | 434 | ||
| @@ -957,7 +960,52 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, | |||
| 957 | EXPORT_SYMBOL(iucv_message_purge); | 960 | EXPORT_SYMBOL(iucv_message_purge); |
| 958 | 961 | ||
| 959 | /** | 962 | /** |
| 960 | * iucv_message_receive | 963 | * iucv_message_receive_iprmdata |
| 964 | * @path: address of iucv path structure | ||
| 965 | * @msg: address of iucv msg structure | ||
| 966 | * @flags: how the message is received (IUCV_IPBUFLST) | ||
| 967 | * @buffer: address of data buffer or address of struct iucv_array | ||
| 968 | * @size: length of data buffer | ||
| 969 | * @residual: | ||
| 970 | * | ||
| 971 | * Internal function used by iucv_message_receive and __iucv_message_receive | ||
| 972 | * to receive RMDATA data stored in struct iucv_message. | ||
| 973 | */ | ||
| 974 | static int iucv_message_receive_iprmdata(struct iucv_path *path, | ||
| 975 | struct iucv_message *msg, | ||
| 976 | u8 flags, void *buffer, | ||
| 977 | size_t size, size_t *residual) | ||
| 978 | { | ||
| 979 | struct iucv_array *array; | ||
| 980 | u8 *rmmsg; | ||
| 981 | size_t copy; | ||
| 982 | |||
| 983 | /* | ||
| 984 | * Message is 8 bytes long and has been stored to the | ||
| 985 | * message descriptor itself. | ||
| 986 | */ | ||
| 987 | if (residual) | ||
| 988 | *residual = abs(size - 8); | ||
| 989 | rmmsg = msg->rmmsg; | ||
| 990 | if (flags & IUCV_IPBUFLST) { | ||
| 991 | /* Copy to struct iucv_array. */ | ||
| 992 | size = (size < 8) ? size : 8; | ||
| 993 | for (array = buffer; size > 0; array++) { | ||
| 994 | copy = min_t(size_t, size, array->length); | ||
| 995 | memcpy((u8 *)(addr_t) array->address, | ||
| 996 | rmmsg, copy); | ||
| 997 | rmmsg += copy; | ||
| 998 | size -= copy; | ||
| 999 | } | ||
| 1000 | } else { | ||
| 1001 | /* Copy to direct buffer. */ | ||
| 1002 | memcpy(buffer, rmmsg, min_t(size_t, size, 8)); | ||
| 1003 | } | ||
| 1004 | return 0; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | /** | ||
| 1008 | * __iucv_message_receive | ||
| 961 | * @path: address of iucv path structure | 1009 | * @path: address of iucv path structure |
| 962 | * @msg: address of iucv msg structure | 1010 | * @msg: address of iucv msg structure |
| 963 | * @flags: how the message is received (IUCV_IPBUFLST) | 1011 | * @flags: how the message is received (IUCV_IPBUFLST) |
| @@ -969,44 +1017,19 @@ EXPORT_SYMBOL(iucv_message_purge); | |||
| 969 | * established paths. This function will deal with RMDATA messages | 1017 | * established paths. This function will deal with RMDATA messages |
| 970 | * embedded in struct iucv_message as well. | 1018 | * embedded in struct iucv_message as well. |
| 971 | * | 1019 | * |
| 1020 | * Locking: no locking | ||
| 1021 | * | ||
| 972 | * Returns the result from the CP IUCV call. | 1022 | * Returns the result from the CP IUCV call. |
| 973 | */ | 1023 | */ |
| 974 | int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | 1024 | int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, |
| 975 | u8 flags, void *buffer, size_t size, size_t *residual) | 1025 | u8 flags, void *buffer, size_t size, size_t *residual) |
| 976 | { | 1026 | { |
| 977 | union iucv_param *parm; | 1027 | union iucv_param *parm; |
| 978 | struct iucv_array *array; | ||
| 979 | u8 *rmmsg; | ||
| 980 | size_t copy; | ||
| 981 | int rc; | 1028 | int rc; |
| 982 | 1029 | ||
| 983 | if (msg->flags & IUCV_IPRMDATA) { | 1030 | if (msg->flags & IUCV_IPRMDATA) |
| 984 | /* | 1031 | return iucv_message_receive_iprmdata(path, msg, flags, |
| 985 | * Message is 8 bytes long and has been stored to the | 1032 | buffer, size, residual); |
| 986 | * message descriptor itself. | ||
| 987 | */ | ||
| 988 | rc = (size < 8) ? 5 : 0; | ||
| 989 | if (residual) | ||
| 990 | *residual = abs(size - 8); | ||
| 991 | rmmsg = msg->rmmsg; | ||
| 992 | if (flags & IUCV_IPBUFLST) { | ||
| 993 | /* Copy to struct iucv_array. */ | ||
| 994 | size = (size < 8) ? size : 8; | ||
| 995 | for (array = buffer; size > 0; array++) { | ||
| 996 | copy = min_t(size_t, size, array->length); | ||
| 997 | memcpy((u8 *)(addr_t) array->address, | ||
| 998 | rmmsg, copy); | ||
| 999 | rmmsg += copy; | ||
| 1000 | size -= copy; | ||
| 1001 | } | ||
| 1002 | } else { | ||
| 1003 | /* Copy to direct buffer. */ | ||
| 1004 | memcpy(buffer, rmmsg, min_t(size_t, size, 8)); | ||
| 1005 | } | ||
| 1006 | return 0; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | local_bh_disable(); | ||
| 1010 | parm = iucv_param[smp_processor_id()]; | 1033 | parm = iucv_param[smp_processor_id()]; |
| 1011 | memset(parm, 0, sizeof(union iucv_param)); | 1034 | memset(parm, 0, sizeof(union iucv_param)); |
| 1012 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; | 1035 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; |
| @@ -1022,6 +1045,37 @@ int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | |||
| 1022 | if (residual) | 1045 | if (residual) |
| 1023 | *residual = parm->db.ipbfln1f; | 1046 | *residual = parm->db.ipbfln1f; |
| 1024 | } | 1047 | } |
| 1048 | return rc; | ||
| 1049 | } | ||
| 1050 | EXPORT_SYMBOL(__iucv_message_receive); | ||
| 1051 | |||
| 1052 | /** | ||
| 1053 | * iucv_message_receive | ||
| 1054 | * @path: address of iucv path structure | ||
| 1055 | * @msg: address of iucv msg structure | ||
| 1056 | * @flags: how the message is received (IUCV_IPBUFLST) | ||
| 1057 | * @buffer: address of data buffer or address of struct iucv_array | ||
| 1058 | * @size: length of data buffer | ||
| 1059 | * @residual: | ||
| 1060 | * | ||
| 1061 | * This function receives messages that are being sent to you over | ||
| 1062 | * established paths. This function will deal with RMDATA messages | ||
| 1063 | * embedded in struct iucv_message as well. | ||
| 1064 | * | ||
| 1065 | * Locking: local_bh_enable/local_bh_disable | ||
| 1066 | * | ||
| 1067 | * Returns the result from the CP IUCV call. | ||
| 1068 | */ | ||
| 1069 | int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | ||
| 1070 | u8 flags, void *buffer, size_t size, size_t *residual) | ||
| 1071 | { | ||
| 1072 | int rc; | ||
| 1073 | |||
| 1074 | if (msg->flags & IUCV_IPRMDATA) | ||
| 1075 | return iucv_message_receive_iprmdata(path, msg, flags, | ||
| 1076 | buffer, size, residual); | ||
| 1077 | local_bh_disable(); | ||
| 1078 | rc = __iucv_message_receive(path, msg, flags, buffer, size, residual); | ||
| 1025 | local_bh_enable(); | 1079 | local_bh_enable(); |
| 1026 | return rc; | 1080 | return rc; |
| 1027 | } | 1081 | } |
| @@ -1101,7 +1155,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, | |||
| 1101 | EXPORT_SYMBOL(iucv_message_reply); | 1155 | EXPORT_SYMBOL(iucv_message_reply); |
| 1102 | 1156 | ||
| 1103 | /** | 1157 | /** |
| 1104 | * iucv_message_send | 1158 | * __iucv_message_send |
| 1105 | * @path: address of iucv path structure | 1159 | * @path: address of iucv path structure |
| 1106 | * @msg: address of iucv msg structure | 1160 | * @msg: address of iucv msg structure |
| 1107 | * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) | 1161 | * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) |
| @@ -1113,15 +1167,16 @@ EXPORT_SYMBOL(iucv_message_reply); | |||
| 1113 | * transmitted is in a buffer and this is a one-way message and the | 1167 | * transmitted is in a buffer and this is a one-way message and the |
| 1114 | * receiver will not reply to the message. | 1168 | * receiver will not reply to the message. |
| 1115 | * | 1169 | * |
| 1170 | * Locking: no locking | ||
| 1171 | * | ||
| 1116 | * Returns the result from the CP IUCV call. | 1172 | * Returns the result from the CP IUCV call. |
| 1117 | */ | 1173 | */ |
| 1118 | int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | 1174 | int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, |
| 1119 | u8 flags, u32 srccls, void *buffer, size_t size) | 1175 | u8 flags, u32 srccls, void *buffer, size_t size) |
| 1120 | { | 1176 | { |
| 1121 | union iucv_param *parm; | 1177 | union iucv_param *parm; |
| 1122 | int rc; | 1178 | int rc; |
| 1123 | 1179 | ||
| 1124 | local_bh_disable(); | ||
| 1125 | parm = iucv_param[smp_processor_id()]; | 1180 | parm = iucv_param[smp_processor_id()]; |
| 1126 | memset(parm, 0, sizeof(union iucv_param)); | 1181 | memset(parm, 0, sizeof(union iucv_param)); |
| 1127 | if (flags & IUCV_IPRMDATA) { | 1182 | if (flags & IUCV_IPRMDATA) { |
| @@ -1144,6 +1199,34 @@ int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | |||
| 1144 | rc = iucv_call_b2f0(IUCV_SEND, parm); | 1199 | rc = iucv_call_b2f0(IUCV_SEND, parm); |
| 1145 | if (!rc) | 1200 | if (!rc) |
| 1146 | msg->id = parm->db.ipmsgid; | 1201 | msg->id = parm->db.ipmsgid; |
| 1202 | return rc; | ||
| 1203 | } | ||
| 1204 | EXPORT_SYMBOL(__iucv_message_send); | ||
| 1205 | |||
| 1206 | /** | ||
| 1207 | * iucv_message_send | ||
| 1208 | * @path: address of iucv path structure | ||
| 1209 | * @msg: address of iucv msg structure | ||
| 1210 | * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) | ||
| 1211 | * @srccls: source class of message | ||
| 1212 | * @buffer: address of send buffer or address of struct iucv_array | ||
| 1213 | * @size: length of send buffer | ||
| 1214 | * | ||
| 1215 | * This function transmits data to another application. Data to be | ||
| 1216 | * transmitted is in a buffer and this is a one-way message and the | ||
| 1217 | * receiver will not reply to the message. | ||
| 1218 | * | ||
| 1219 | * Locking: local_bh_enable/local_bh_disable | ||
| 1220 | * | ||
| 1221 | * Returns the result from the CP IUCV call. | ||
| 1222 | */ | ||
| 1223 | int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | ||
| 1224 | u8 flags, u32 srccls, void *buffer, size_t size) | ||
| 1225 | { | ||
| 1226 | int rc; | ||
| 1227 | |||
| 1228 | local_bh_disable(); | ||
| 1229 | rc = __iucv_message_send(path, msg, flags, srccls, buffer, size); | ||
| 1147 | local_bh_enable(); | 1230 | local_bh_enable(); |
| 1148 | return rc; | 1231 | return rc; |
| 1149 | } | 1232 | } |
| @@ -1572,7 +1655,7 @@ static void iucv_external_interrupt(u16 code) | |||
| 1572 | BUG_ON(p->iptype < 0x01 || p->iptype > 0x09); | 1655 | BUG_ON(p->iptype < 0x01 || p->iptype > 0x09); |
| 1573 | work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC); | 1656 | work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC); |
| 1574 | if (!work) { | 1657 | if (!work) { |
| 1575 | printk(KERN_WARNING "iucv_external_interrupt: out of memory\n"); | 1658 | pr_warning("iucv_external_interrupt: out of memory\n"); |
| 1576 | return; | 1659 | return; |
| 1577 | } | 1660 | } |
| 1578 | memcpy(&work->data, p, sizeof(work->data)); | 1661 | memcpy(&work->data, p, sizeof(work->data)); |
