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)); |