diff options
Diffstat (limited to 'drivers/s390/char/monreader.c')
-rw-r--r-- | drivers/s390/char/monreader.c | 78 |
1 files changed, 11 insertions, 67 deletions
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 1e1f50655bbf..35fd8dfcaaa6 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c | |||
@@ -3,14 +3,14 @@ | |||
3 | * | 3 | * |
4 | * Character device driver for reading z/VM *MONITOR service records. | 4 | * Character device driver for reading z/VM *MONITOR service records. |
5 | * | 5 | * |
6 | * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. | 6 | * Copyright IBM Corp. 2004, 2008 |
7 | * | 7 | * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> |
8 | * Author: Gerald Schaefer <geraldsc@de.ibm.com> | ||
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/module.h> | 10 | #include <linux/module.h> |
12 | #include <linux/moduleparam.h> | 11 | #include <linux/moduleparam.h> |
13 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/smp_lock.h> | ||
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
@@ -18,12 +18,11 @@ | |||
18 | #include <linux/ctype.h> | 18 | #include <linux/ctype.h> |
19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/poll.h> | ||
22 | #include <net/iucv/iucv.h> | ||
21 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
22 | #include <asm/ebcdic.h> | 24 | #include <asm/ebcdic.h> |
23 | #include <asm/extmem.h> | 25 | #include <asm/extmem.h> |
24 | #include <linux/poll.h> | ||
25 | #include <net/iucv/iucv.h> | ||
26 | |||
27 | 26 | ||
28 | //#define MON_DEBUG /* Debug messages on/off */ | 27 | //#define MON_DEBUG /* Debug messages on/off */ |
29 | 28 | ||
@@ -152,10 +151,7 @@ static int mon_check_mca(struct mon_msg *monmsg) | |||
152 | (mon_mca_end(monmsg) > mon_dcss_end) || | 151 | (mon_mca_end(monmsg) > mon_dcss_end) || |
153 | (mon_mca_start(monmsg) < mon_dcss_start) || | 152 | (mon_mca_start(monmsg) < mon_dcss_start) || |
154 | ((mon_mca_type(monmsg, 1) == 0) && (mon_mca_type(monmsg, 2) == 0))) | 153 | ((mon_mca_type(monmsg, 1) == 0) && (mon_mca_type(monmsg, 2) == 0))) |
155 | { | ||
156 | P_DEBUG("READ, IGNORED INVALID MCA\n\n"); | ||
157 | return -EINVAL; | 154 | return -EINVAL; |
158 | } | ||
159 | return 0; | 155 | return 0; |
160 | } | 156 | } |
161 | 157 | ||
@@ -164,10 +160,6 @@ static int mon_send_reply(struct mon_msg *monmsg, | |||
164 | { | 160 | { |
165 | int rc; | 161 | int rc; |
166 | 162 | ||
167 | P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = " | ||
168 | "0x%08X\n\n", | ||
169 | monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); | ||
170 | |||
171 | rc = iucv_message_reply(monpriv->path, &monmsg->msg, | 163 | rc = iucv_message_reply(monpriv->path, &monmsg->msg, |
172 | IUCV_IPRMDATA, NULL, 0); | 164 | IUCV_IPRMDATA, NULL, 0); |
173 | atomic_dec(&monpriv->msglim_count); | 165 | atomic_dec(&monpriv->msglim_count); |
@@ -202,15 +194,12 @@ static struct mon_private *mon_alloc_mem(void) | |||
202 | struct mon_private *monpriv; | 194 | struct mon_private *monpriv; |
203 | 195 | ||
204 | monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); | 196 | monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); |
205 | if (!monpriv) { | 197 | if (!monpriv) |
206 | P_ERROR("no memory for monpriv\n"); | ||
207 | return NULL; | 198 | return NULL; |
208 | } | ||
209 | for (i = 0; i < MON_MSGLIM; i++) { | 199 | for (i = 0; i < MON_MSGLIM; i++) { |
210 | monpriv->msg_array[i] = kzalloc(sizeof(struct mon_msg), | 200 | monpriv->msg_array[i] = kzalloc(sizeof(struct mon_msg), |
211 | GFP_KERNEL); | 201 | GFP_KERNEL); |
212 | if (!monpriv->msg_array[i]) { | 202 | if (!monpriv->msg_array[i]) { |
213 | P_ERROR("open, no memory for msg_array\n"); | ||
214 | mon_free_mem(monpriv); | 203 | mon_free_mem(monpriv); |
215 | return NULL; | 204 | return NULL; |
216 | } | 205 | } |
@@ -218,41 +207,10 @@ static struct mon_private *mon_alloc_mem(void) | |||
218 | return monpriv; | 207 | return monpriv; |
219 | } | 208 | } |
220 | 209 | ||
221 | static inline void mon_read_debug(struct mon_msg *monmsg, | ||
222 | struct mon_private *monpriv) | ||
223 | { | ||
224 | #ifdef MON_DEBUG | ||
225 | u8 msg_type[2], mca_type; | ||
226 | unsigned long records_len; | ||
227 | |||
228 | records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1; | ||
229 | |||
230 | memcpy(msg_type, &monmsg->msg.class, 2); | ||
231 | EBCASC(msg_type, 2); | ||
232 | mca_type = mon_mca_type(monmsg, 0); | ||
233 | EBCASC(&mca_type, 1); | ||
234 | |||
235 | P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n", | ||
236 | monpriv->read_index, monpriv->write_index); | ||
237 | P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n", | ||
238 | monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); | ||
239 | P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n", | ||
240 | msg_type[0], msg_type[1], mca_type ? mca_type : 'X', | ||
241 | mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2)); | ||
242 | P_DEBUG("read, MCA: start = 0x%lX, end = 0x%lX\n", | ||
243 | mon_mca_start(monmsg), mon_mca_end(monmsg)); | ||
244 | P_DEBUG("read, REC: start = 0x%X, end = 0x%X, len = %lu\n\n", | ||
245 | mon_rec_start(monmsg), mon_rec_end(monmsg), records_len); | ||
246 | if (mon_mca_size(monmsg) > 12) | ||
247 | P_DEBUG("READ, MORE THAN ONE MCA\n\n"); | ||
248 | #endif | ||
249 | } | ||
250 | |||
251 | static inline void mon_next_mca(struct mon_msg *monmsg) | 210 | static inline void mon_next_mca(struct mon_msg *monmsg) |
252 | { | 211 | { |
253 | if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) | 212 | if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) |
254 | return; | 213 | return; |
255 | P_DEBUG("READ, NEXT MCA\n\n"); | ||
256 | monmsg->mca_offset += 12; | 214 | monmsg->mca_offset += 12; |
257 | monmsg->pos = 0; | 215 | monmsg->pos = 0; |
258 | } | 216 | } |
@@ -269,7 +227,6 @@ static struct mon_msg *mon_next_message(struct mon_private *monpriv) | |||
269 | monmsg->msglim_reached = 0; | 227 | monmsg->msglim_reached = 0; |
270 | monmsg->pos = 0; | 228 | monmsg->pos = 0; |
271 | monmsg->mca_offset = 0; | 229 | monmsg->mca_offset = 0; |
272 | P_WARNING("read, message limit reached\n"); | ||
273 | monpriv->read_index = (monpriv->read_index + 1) % | 230 | monpriv->read_index = (monpriv->read_index + 1) % |
274 | MON_MSGLIM; | 231 | MON_MSGLIM; |
275 | atomic_dec(&monpriv->read_ready); | 232 | atomic_dec(&monpriv->read_ready); |
@@ -286,10 +243,6 @@ static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) | |||
286 | { | 243 | { |
287 | struct mon_private *monpriv = path->private; | 244 | struct mon_private *monpriv = path->private; |
288 | 245 | ||
289 | P_DEBUG("IUCV connection completed\n"); | ||
290 | P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = " | ||
291 | "0x%02X, Sample = 0x%02X\n", | ||
292 | ipuser[0], ipuser[1], ipuser[2]); | ||
293 | atomic_set(&monpriv->iucv_connected, 1); | 246 | atomic_set(&monpriv->iucv_connected, 1); |
294 | wake_up(&mon_conn_wait_queue); | 247 | wake_up(&mon_conn_wait_queue); |
295 | } | 248 | } |
@@ -310,7 +263,6 @@ static void mon_iucv_message_pending(struct iucv_path *path, | |||
310 | { | 263 | { |
311 | struct mon_private *monpriv = path->private; | 264 | struct mon_private *monpriv = path->private; |
312 | 265 | ||
313 | P_DEBUG("IUCV message pending\n"); | ||
314 | memcpy(&monpriv->msg_array[monpriv->write_index]->msg, | 266 | memcpy(&monpriv->msg_array[monpriv->write_index]->msg, |
315 | msg, sizeof(*msg)); | 267 | msg, sizeof(*msg)); |
316 | if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { | 268 | if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { |
@@ -340,6 +292,7 @@ static int mon_open(struct inode *inode, struct file *filp) | |||
340 | /* | 292 | /* |
341 | * only one user allowed | 293 | * only one user allowed |
342 | */ | 294 | */ |
295 | lock_kernel(); | ||
343 | rc = -EBUSY; | 296 | rc = -EBUSY; |
344 | if (test_and_set_bit(MON_IN_USE, &mon_in_use)) | 297 | if (test_and_set_bit(MON_IN_USE, &mon_in_use)) |
345 | goto out; | 298 | goto out; |
@@ -375,8 +328,8 @@ static int mon_open(struct inode *inode, struct file *filp) | |||
375 | rc = -EIO; | 328 | rc = -EIO; |
376 | goto out_path; | 329 | goto out_path; |
377 | } | 330 | } |
378 | P_INFO("open, established connection to *MONITOR service\n\n"); | ||
379 | filp->private_data = monpriv; | 331 | filp->private_data = monpriv; |
332 | unlock_kernel(); | ||
380 | return nonseekable_open(inode, filp); | 333 | return nonseekable_open(inode, filp); |
381 | 334 | ||
382 | out_path: | 335 | out_path: |
@@ -386,6 +339,7 @@ out_priv: | |||
386 | out_use: | 339 | out_use: |
387 | clear_bit(MON_IN_USE, &mon_in_use); | 340 | clear_bit(MON_IN_USE, &mon_in_use); |
388 | out: | 341 | out: |
342 | unlock_kernel(); | ||
389 | return rc; | 343 | return rc; |
390 | } | 344 | } |
391 | 345 | ||
@@ -400,8 +354,6 @@ static int mon_close(struct inode *inode, struct file *filp) | |||
400 | rc = iucv_path_sever(monpriv->path, user_data_sever); | 354 | rc = iucv_path_sever(monpriv->path, user_data_sever); |
401 | if (rc) | 355 | if (rc) |
402 | P_ERROR("close, iucv_sever failed with rc = %i\n", rc); | 356 | P_ERROR("close, iucv_sever failed with rc = %i\n", rc); |
403 | else | ||
404 | P_INFO("close, terminated connection to *MONITOR service\n"); | ||
405 | 357 | ||
406 | atomic_set(&monpriv->iucv_severed, 0); | 358 | atomic_set(&monpriv->iucv_severed, 0); |
407 | atomic_set(&monpriv->iucv_connected, 0); | 359 | atomic_set(&monpriv->iucv_connected, 0); |
@@ -442,10 +394,8 @@ static ssize_t mon_read(struct file *filp, char __user *data, | |||
442 | monmsg = monpriv->msg_array[monpriv->read_index]; | 394 | monmsg = monpriv->msg_array[monpriv->read_index]; |
443 | } | 395 | } |
444 | 396 | ||
445 | if (!monmsg->pos) { | 397 | if (!monmsg->pos) |
446 | monmsg->pos = mon_mca_start(monmsg) + monmsg->mca_offset; | 398 | monmsg->pos = mon_mca_start(monmsg) + monmsg->mca_offset; |
447 | mon_read_debug(monmsg, monpriv); | ||
448 | } | ||
449 | if (mon_check_mca(monmsg)) | 399 | if (mon_check_mca(monmsg)) |
450 | goto reply; | 400 | goto reply; |
451 | 401 | ||
@@ -531,7 +481,6 @@ static int __init mon_init(void) | |||
531 | P_ERROR("failed to register with iucv driver\n"); | 481 | P_ERROR("failed to register with iucv driver\n"); |
532 | return rc; | 482 | return rc; |
533 | } | 483 | } |
534 | P_INFO("open, registered with IUCV\n"); | ||
535 | 484 | ||
536 | rc = segment_type(mon_dcss_name); | 485 | rc = segment_type(mon_dcss_name); |
537 | if (rc < 0) { | 486 | if (rc < 0) { |
@@ -555,13 +504,8 @@ static int __init mon_init(void) | |||
555 | dcss_mkname(mon_dcss_name, &user_data_connect[8]); | 504 | dcss_mkname(mon_dcss_name, &user_data_connect[8]); |
556 | 505 | ||
557 | rc = misc_register(&mon_dev); | 506 | rc = misc_register(&mon_dev); |
558 | if (rc < 0 ) { | 507 | if (rc < 0 ) |
559 | P_ERROR("misc_register failed, rc = %i\n", rc); | ||
560 | goto out; | 508 | goto out; |
561 | } | ||
562 | P_INFO("Loaded segment %s from %p to %p, size = %lu Byte\n", | ||
563 | mon_dcss_name, (void *) mon_dcss_start, (void *) mon_dcss_end, | ||
564 | mon_dcss_end - mon_dcss_start + 1); | ||
565 | return 0; | 509 | return 0; |
566 | 510 | ||
567 | out: | 511 | out: |