diff options
Diffstat (limited to 'drivers/s390/char/vmlogrdr.c')
-rw-r--r-- | drivers/s390/char/vmlogrdr.c | 279 |
1 files changed, 127 insertions, 152 deletions
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 4f894dc2373b..8432a76b961e 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * character device driver for reading z/VM system service records | 3 | * character device driver for reading z/VM system service records |
4 | * | 4 | * |
5 | * | 5 | * |
6 | * Copyright (C) 2004 IBM Corporation | 6 | * Copyright 2004 IBM Corporation |
7 | * character device driver for reading z/VM system service records, | 7 | * character device driver for reading z/VM system service records, |
8 | * Version 1.0 | 8 | * Version 1.0 |
9 | * Author(s): Xenia Tkatschow <xenia@us.ibm.com> | 9 | * Author(s): Xenia Tkatschow <xenia@us.ibm.com> |
@@ -21,7 +21,7 @@ | |||
21 | #include <asm/cpcmd.h> | 21 | #include <asm/cpcmd.h> |
22 | #include <asm/debug.h> | 22 | #include <asm/debug.h> |
23 | #include <asm/ebcdic.h> | 23 | #include <asm/ebcdic.h> |
24 | #include "../net/iucv.h" | 24 | #include <net/iucv/iucv.h> |
25 | #include <linux/kmod.h> | 25 | #include <linux/kmod.h> |
26 | #include <linux/cdev.h> | 26 | #include <linux/cdev.h> |
27 | #include <linux/device.h> | 27 | #include <linux/device.h> |
@@ -60,12 +60,11 @@ struct vmlogrdr_priv_t { | |||
60 | char system_service[8]; | 60 | char system_service[8]; |
61 | char internal_name[8]; | 61 | char internal_name[8]; |
62 | char recording_name[8]; | 62 | char recording_name[8]; |
63 | u16 pathid; | 63 | struct iucv_path *path; |
64 | int connection_established; | 64 | int connection_established; |
65 | int iucv_path_severed; | 65 | int iucv_path_severed; |
66 | iucv_MessagePending local_interrupt_buffer; | 66 | struct iucv_message local_interrupt_buffer; |
67 | atomic_t receive_ready; | 67 | atomic_t receive_ready; |
68 | iucv_handle_t iucv_handle; | ||
69 | int minor_num; | 68 | int minor_num; |
70 | char * buffer; | 69 | char * buffer; |
71 | char * current_position; | 70 | char * current_position; |
@@ -97,37 +96,19 @@ static struct file_operations vmlogrdr_fops = { | |||
97 | }; | 96 | }; |
98 | 97 | ||
99 | 98 | ||
100 | static u8 iucvMagic[16] = { | 99 | static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 ipuser[16]); |
101 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | 100 | static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 ipuser[16]); |
102 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 | 101 | static void vmlogrdr_iucv_message_pending(struct iucv_path *, |
103 | }; | 102 | struct iucv_message *); |
104 | 103 | ||
105 | 104 | ||
106 | static u8 mask[] = { | 105 | static struct iucv_handler vmlogrdr_iucv_handler = { |
107 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 106 | .path_complete = vmlogrdr_iucv_path_complete, |
108 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 107 | .path_severed = vmlogrdr_iucv_path_severed, |
109 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 108 | .message_pending = vmlogrdr_iucv_message_pending, |
110 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
111 | }; | 109 | }; |
112 | 110 | ||
113 | 111 | ||
114 | static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
115 | |||
116 | |||
117 | static void | ||
118 | vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data); | ||
119 | static void | ||
120 | vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data); | ||
121 | static void | ||
122 | vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data); | ||
123 | |||
124 | |||
125 | static iucv_interrupt_ops_t vmlogrdr_iucvops = { | ||
126 | .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete, | ||
127 | .ConnectionSevered = vmlogrdr_iucv_ConnectionSevered, | ||
128 | .MessagePending = vmlogrdr_iucv_MessagePending, | ||
129 | }; | ||
130 | |||
131 | static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); | 112 | static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); |
132 | static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); | 113 | static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); |
133 | 114 | ||
@@ -176,28 +157,29 @@ static struct cdev *vmlogrdr_cdev = NULL; | |||
176 | static int recording_class_AB; | 157 | static int recording_class_AB; |
177 | 158 | ||
178 | 159 | ||
179 | static void | 160 | static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) |
180 | vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib, | ||
181 | void * pgm_data) | ||
182 | { | 161 | { |
183 | struct vmlogrdr_priv_t * logptr = pgm_data; | 162 | struct vmlogrdr_priv_t * logptr = path->private; |
163 | |||
184 | spin_lock(&logptr->priv_lock); | 164 | spin_lock(&logptr->priv_lock); |
185 | logptr->connection_established = 1; | 165 | logptr->connection_established = 1; |
186 | spin_unlock(&logptr->priv_lock); | 166 | spin_unlock(&logptr->priv_lock); |
187 | wake_up(&conn_wait_queue); | 167 | wake_up(&conn_wait_queue); |
188 | return; | ||
189 | } | 168 | } |
190 | 169 | ||
191 | 170 | ||
192 | static void | 171 | static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) |
193 | vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) | ||
194 | { | 172 | { |
195 | u8 reason = (u8) eib->ipuser[8]; | 173 | struct vmlogrdr_priv_t * logptr = path->private; |
196 | struct vmlogrdr_priv_t * logptr = pgm_data; | 174 | u8 reason = (u8) ipuser[8]; |
197 | 175 | ||
198 | printk (KERN_ERR "vmlogrdr: connection severed with" | 176 | printk (KERN_ERR "vmlogrdr: connection severed with" |
199 | " reason %i\n", reason); | 177 | " reason %i\n", reason); |
200 | 178 | ||
179 | iucv_path_sever(path, NULL); | ||
180 | kfree(path); | ||
181 | logptr->path = NULL; | ||
182 | |||
201 | spin_lock(&logptr->priv_lock); | 183 | spin_lock(&logptr->priv_lock); |
202 | logptr->connection_established = 0; | 184 | logptr->connection_established = 0; |
203 | logptr->iucv_path_severed = 1; | 185 | logptr->iucv_path_severed = 1; |
@@ -209,10 +191,10 @@ vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) | |||
209 | } | 191 | } |
210 | 192 | ||
211 | 193 | ||
212 | static void | 194 | static void vmlogrdr_iucv_message_pending(struct iucv_path *path, |
213 | vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) | 195 | struct iucv_message *msg) |
214 | { | 196 | { |
215 | struct vmlogrdr_priv_t * logptr = pgm_data; | 197 | struct vmlogrdr_priv_t * logptr = path->private; |
216 | 198 | ||
217 | /* | 199 | /* |
218 | * This function is the bottom half so it should be quick. | 200 | * This function is the bottom half so it should be quick. |
@@ -220,15 +202,15 @@ vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) | |||
220 | * the usage count | 202 | * the usage count |
221 | */ | 203 | */ |
222 | spin_lock(&logptr->priv_lock); | 204 | spin_lock(&logptr->priv_lock); |
223 | memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib)); | 205 | memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg)); |
224 | atomic_inc(&logptr->receive_ready); | 206 | atomic_inc(&logptr->receive_ready); |
225 | spin_unlock(&logptr->priv_lock); | 207 | spin_unlock(&logptr->priv_lock); |
226 | wake_up_interruptible(&read_wait_queue); | 208 | wake_up_interruptible(&read_wait_queue); |
227 | } | 209 | } |
228 | 210 | ||
229 | 211 | ||
230 | static int | 212 | static int vmlogrdr_get_recording_class_AB(void) |
231 | vmlogrdr_get_recording_class_AB(void) { | 213 | { |
232 | char cp_command[]="QUERY COMMAND RECORDING "; | 214 | char cp_command[]="QUERY COMMAND RECORDING "; |
233 | char cp_response[80]; | 215 | char cp_response[80]; |
234 | char *tail; | 216 | char *tail; |
@@ -258,8 +240,9 @@ vmlogrdr_get_recording_class_AB(void) { | |||
258 | } | 240 | } |
259 | 241 | ||
260 | 242 | ||
261 | static int | 243 | static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, |
262 | vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { | 244 | int action, int purge) |
245 | { | ||
263 | 246 | ||
264 | char cp_command[80]; | 247 | char cp_command[80]; |
265 | char cp_response[160]; | 248 | char cp_response[160]; |
@@ -317,8 +300,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { | |||
317 | } | 300 | } |
318 | 301 | ||
319 | 302 | ||
320 | static int | 303 | static int vmlogrdr_open (struct inode *inode, struct file *filp) |
321 | vmlogrdr_open (struct inode *inode, struct file *filp) | ||
322 | { | 304 | { |
323 | int dev_num = 0; | 305 | int dev_num = 0; |
324 | struct vmlogrdr_priv_t * logptr = NULL; | 306 | struct vmlogrdr_priv_t * logptr = NULL; |
@@ -328,10 +310,7 @@ vmlogrdr_open (struct inode *inode, struct file *filp) | |||
328 | dev_num = iminor(inode); | 310 | dev_num = iminor(inode); |
329 | if (dev_num > MAXMINOR) | 311 | if (dev_num > MAXMINOR) |
330 | return -ENODEV; | 312 | return -ENODEV; |
331 | |||
332 | logptr = &sys_ser[dev_num]; | 313 | logptr = &sys_ser[dev_num]; |
333 | if (logptr == NULL) | ||
334 | return -ENODEV; | ||
335 | 314 | ||
336 | /* | 315 | /* |
337 | * only allow for blocking reads to be open | 316 | * only allow for blocking reads to be open |
@@ -344,52 +323,38 @@ vmlogrdr_open (struct inode *inode, struct file *filp) | |||
344 | if (logptr->dev_in_use) { | 323 | if (logptr->dev_in_use) { |
345 | spin_unlock_bh(&logptr->priv_lock); | 324 | spin_unlock_bh(&logptr->priv_lock); |
346 | return -EBUSY; | 325 | return -EBUSY; |
347 | } else { | ||
348 | logptr->dev_in_use = 1; | ||
349 | spin_unlock_bh(&logptr->priv_lock); | ||
350 | } | 326 | } |
351 | 327 | logptr->dev_in_use = 1; | |
328 | logptr->connection_established = 0; | ||
329 | logptr->iucv_path_severed = 0; | ||
352 | atomic_set(&logptr->receive_ready, 0); | 330 | atomic_set(&logptr->receive_ready, 0); |
353 | logptr->buffer_free = 1; | 331 | logptr->buffer_free = 1; |
332 | spin_unlock_bh(&logptr->priv_lock); | ||
354 | 333 | ||
355 | /* set the file options */ | 334 | /* set the file options */ |
356 | filp->private_data = logptr; | 335 | filp->private_data = logptr; |
357 | filp->f_op = &vmlogrdr_fops; | 336 | filp->f_op = &vmlogrdr_fops; |
358 | 337 | ||
359 | /* start recording for this service*/ | 338 | /* start recording for this service*/ |
360 | ret=0; | 339 | if (logptr->autorecording) { |
361 | if (logptr->autorecording) | ||
362 | ret = vmlogrdr_recording(logptr,1,logptr->autopurge); | 340 | ret = vmlogrdr_recording(logptr,1,logptr->autopurge); |
363 | if (ret) | 341 | if (ret) |
364 | printk (KERN_WARNING "vmlogrdr: failed to start " | 342 | printk (KERN_WARNING "vmlogrdr: failed to start " |
365 | "recording automatically\n"); | 343 | "recording automatically\n"); |
366 | |||
367 | /* Register with iucv driver */ | ||
368 | logptr->iucv_handle = iucv_register_program(iucvMagic, | ||
369 | logptr->system_service, mask, &vmlogrdr_iucvops, | ||
370 | logptr); | ||
371 | |||
372 | if (logptr->iucv_handle == NULL) { | ||
373 | printk (KERN_ERR "vmlogrdr: failed to register with" | ||
374 | "iucv driver\n"); | ||
375 | goto not_registered; | ||
376 | } | 344 | } |
377 | 345 | ||
378 | /* create connection to the system service */ | 346 | /* create connection to the system service */ |
379 | spin_lock_bh(&logptr->priv_lock); | 347 | logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL); |
380 | logptr->connection_established = 0; | 348 | if (!logptr->path) |
381 | logptr->iucv_path_severed = 0; | 349 | goto out_dev; |
382 | spin_unlock_bh(&logptr->priv_lock); | 350 | connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler, |
383 | 351 | logptr->system_service, NULL, NULL, | |
384 | connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic, | 352 | logptr); |
385 | logptr->system_service, iucv_host, 0, | ||
386 | NULL, NULL, | ||
387 | logptr->iucv_handle, NULL); | ||
388 | if (connect_rc) { | 353 | if (connect_rc) { |
389 | printk (KERN_ERR "vmlogrdr: iucv connection to %s " | 354 | printk (KERN_ERR "vmlogrdr: iucv connection to %s " |
390 | "failed with rc %i \n", logptr->system_service, | 355 | "failed with rc %i \n", logptr->system_service, |
391 | connect_rc); | 356 | connect_rc); |
392 | goto not_connected; | 357 | goto out_path; |
393 | } | 358 | } |
394 | 359 | ||
395 | /* We've issued the connect and now we must wait for a | 360 | /* We've issued the connect and now we must wait for a |
@@ -398,35 +363,28 @@ vmlogrdr_open (struct inode *inode, struct file *filp) | |||
398 | */ | 363 | */ |
399 | wait_event(conn_wait_queue, (logptr->connection_established) | 364 | wait_event(conn_wait_queue, (logptr->connection_established) |
400 | || (logptr->iucv_path_severed)); | 365 | || (logptr->iucv_path_severed)); |
401 | if (logptr->iucv_path_severed) { | 366 | if (logptr->iucv_path_severed) |
402 | goto not_connected; | 367 | goto out_record; |
403 | } | ||
404 | |||
405 | return nonseekable_open(inode, filp); | 368 | return nonseekable_open(inode, filp); |
406 | 369 | ||
407 | not_connected: | 370 | out_record: |
408 | iucv_unregister_program(logptr->iucv_handle); | ||
409 | logptr->iucv_handle = NULL; | ||
410 | not_registered: | ||
411 | if (logptr->autorecording) | 371 | if (logptr->autorecording) |
412 | vmlogrdr_recording(logptr,0,logptr->autopurge); | 372 | vmlogrdr_recording(logptr,0,logptr->autopurge); |
373 | out_path: | ||
374 | kfree(logptr->path); /* kfree(NULL) is ok. */ | ||
375 | logptr->path = NULL; | ||
376 | out_dev: | ||
413 | logptr->dev_in_use = 0; | 377 | logptr->dev_in_use = 0; |
414 | return -EIO; | 378 | return -EIO; |
415 | |||
416 | |||
417 | } | 379 | } |
418 | 380 | ||
419 | 381 | ||
420 | static int | 382 | static int vmlogrdr_release (struct inode *inode, struct file *filp) |
421 | vmlogrdr_release (struct inode *inode, struct file *filp) | ||
422 | { | 383 | { |
423 | int ret; | 384 | int ret; |
424 | 385 | ||
425 | struct vmlogrdr_priv_t * logptr = filp->private_data; | 386 | struct vmlogrdr_priv_t * logptr = filp->private_data; |
426 | 387 | ||
427 | iucv_unregister_program(logptr->iucv_handle); | ||
428 | logptr->iucv_handle = NULL; | ||
429 | |||
430 | if (logptr->autorecording) { | 388 | if (logptr->autorecording) { |
431 | ret = vmlogrdr_recording(logptr,0,logptr->autopurge); | 389 | ret = vmlogrdr_recording(logptr,0,logptr->autopurge); |
432 | if (ret) | 390 | if (ret) |
@@ -439,8 +397,8 @@ vmlogrdr_release (struct inode *inode, struct file *filp) | |||
439 | } | 397 | } |
440 | 398 | ||
441 | 399 | ||
442 | static int | 400 | static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) |
443 | vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { | 401 | { |
444 | int rc, *temp; | 402 | int rc, *temp; |
445 | /* we need to keep track of two data sizes here: | 403 | /* we need to keep track of two data sizes here: |
446 | * The number of bytes we need to receive from iucv and | 404 | * The number of bytes we need to receive from iucv and |
@@ -461,8 +419,7 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { | |||
461 | * We need to return the total length of the record | 419 | * We need to return the total length of the record |
462 | * + size of FENCE in the first 4 bytes of the buffer. | 420 | * + size of FENCE in the first 4 bytes of the buffer. |
463 | */ | 421 | */ |
464 | iucv_data_count = | 422 | iucv_data_count = priv->local_interrupt_buffer.length; |
465 | priv->local_interrupt_buffer.ln1msg2.ipbfln1f; | ||
466 | user_data_count = sizeof(int); | 423 | user_data_count = sizeof(int); |
467 | temp = (int*)priv->buffer; | 424 | temp = (int*)priv->buffer; |
468 | *temp= iucv_data_count + sizeof(FENCE); | 425 | *temp= iucv_data_count + sizeof(FENCE); |
@@ -474,14 +431,10 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { | |||
474 | */ | 431 | */ |
475 | if (iucv_data_count > NET_BUFFER_SIZE) | 432 | if (iucv_data_count > NET_BUFFER_SIZE) |
476 | iucv_data_count = NET_BUFFER_SIZE; | 433 | iucv_data_count = NET_BUFFER_SIZE; |
477 | rc = iucv_receive(priv->pathid, | 434 | rc = iucv_message_receive(priv->path, |
478 | priv->local_interrupt_buffer.ipmsgid, | 435 | &priv->local_interrupt_buffer, |
479 | priv->local_interrupt_buffer.iptrgcls, | 436 | 0, buffer, iucv_data_count, |
480 | buffer, | 437 | &priv->residual_length); |
481 | iucv_data_count, | ||
482 | NULL, | ||
483 | NULL, | ||
484 | &priv->residual_length); | ||
485 | spin_unlock_bh(&priv->priv_lock); | 438 | spin_unlock_bh(&priv->priv_lock); |
486 | /* An rc of 5 indicates that the record was bigger then | 439 | /* An rc of 5 indicates that the record was bigger then |
487 | * the buffer, which is OK for us. A 9 indicates that the | 440 | * the buffer, which is OK for us. A 9 indicates that the |
@@ -513,8 +466,8 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { | |||
513 | } | 466 | } |
514 | 467 | ||
515 | 468 | ||
516 | static ssize_t | 469 | static ssize_t vmlogrdr_read(struct file *filp, char __user *data, |
517 | vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) | 470 | size_t count, loff_t * ppos) |
518 | { | 471 | { |
519 | int rc; | 472 | int rc; |
520 | struct vmlogrdr_priv_t * priv = filp->private_data; | 473 | struct vmlogrdr_priv_t * priv = filp->private_data; |
@@ -546,8 +499,10 @@ vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) | |||
546 | return count; | 499 | return count; |
547 | } | 500 | } |
548 | 501 | ||
549 | static ssize_t | 502 | static ssize_t vmlogrdr_autopurge_store(struct device * dev, |
550 | vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { | 503 | struct device_attribute *attr, |
504 | const char * buf, size_t count) | ||
505 | { | ||
551 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 506 | struct vmlogrdr_priv_t *priv = dev->driver_data; |
552 | ssize_t ret = count; | 507 | ssize_t ret = count; |
553 | 508 | ||
@@ -565,8 +520,10 @@ vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, con | |||
565 | } | 520 | } |
566 | 521 | ||
567 | 522 | ||
568 | static ssize_t | 523 | static ssize_t vmlogrdr_autopurge_show(struct device *dev, |
569 | vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) { | 524 | struct device_attribute *attr, |
525 | char *buf) | ||
526 | { | ||
570 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 527 | struct vmlogrdr_priv_t *priv = dev->driver_data; |
571 | return sprintf(buf, "%u\n", priv->autopurge); | 528 | return sprintf(buf, "%u\n", priv->autopurge); |
572 | } | 529 | } |
@@ -576,8 +533,10 @@ static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show, | |||
576 | vmlogrdr_autopurge_store); | 533 | vmlogrdr_autopurge_store); |
577 | 534 | ||
578 | 535 | ||
579 | static ssize_t | 536 | static ssize_t vmlogrdr_purge_store(struct device * dev, |
580 | vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { | 537 | struct device_attribute *attr, |
538 | const char * buf, size_t count) | ||
539 | { | ||
581 | 540 | ||
582 | char cp_command[80]; | 541 | char cp_command[80]; |
583 | char cp_response[80]; | 542 | char cp_response[80]; |
@@ -617,9 +576,10 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c | |||
617 | static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store); | 576 | static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store); |
618 | 577 | ||
619 | 578 | ||
620 | static ssize_t | 579 | static ssize_t vmlogrdr_autorecording_store(struct device *dev, |
621 | vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf, | 580 | struct device_attribute *attr, |
622 | size_t count) { | 581 | const char *buf, size_t count) |
582 | { | ||
623 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 583 | struct vmlogrdr_priv_t *priv = dev->driver_data; |
624 | ssize_t ret = count; | 584 | ssize_t ret = count; |
625 | 585 | ||
@@ -637,8 +597,10 @@ vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, | |||
637 | } | 597 | } |
638 | 598 | ||
639 | 599 | ||
640 | static ssize_t | 600 | static ssize_t vmlogrdr_autorecording_show(struct device *dev, |
641 | vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) { | 601 | struct device_attribute *attr, |
602 | char *buf) | ||
603 | { | ||
642 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 604 | struct vmlogrdr_priv_t *priv = dev->driver_data; |
643 | return sprintf(buf, "%u\n", priv->autorecording); | 605 | return sprintf(buf, "%u\n", priv->autorecording); |
644 | } | 606 | } |
@@ -648,9 +610,10 @@ static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show, | |||
648 | vmlogrdr_autorecording_store); | 610 | vmlogrdr_autorecording_store); |
649 | 611 | ||
650 | 612 | ||
651 | static ssize_t | 613 | static ssize_t vmlogrdr_recording_store(struct device * dev, |
652 | vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { | 614 | struct device_attribute *attr, |
653 | 615 | const char * buf, size_t count) | |
616 | { | ||
654 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 617 | struct vmlogrdr_priv_t *priv = dev->driver_data; |
655 | ssize_t ret; | 618 | ssize_t ret; |
656 | 619 | ||
@@ -675,8 +638,9 @@ vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, con | |||
675 | static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store); | 638 | static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store); |
676 | 639 | ||
677 | 640 | ||
678 | static ssize_t | 641 | static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver, |
679 | vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) { | 642 | char *buf) |
643 | { | ||
680 | 644 | ||
681 | char cp_command[] = "QUERY RECORDING "; | 645 | char cp_command[] = "QUERY RECORDING "; |
682 | int len; | 646 | int len; |
@@ -709,52 +673,63 @@ static struct device_driver vmlogrdr_driver = { | |||
709 | }; | 673 | }; |
710 | 674 | ||
711 | 675 | ||
712 | static int | 676 | static int vmlogrdr_register_driver(void) |
713 | vmlogrdr_register_driver(void) { | 677 | { |
714 | int ret; | 678 | int ret; |
715 | 679 | ||
680 | /* Register with iucv driver */ | ||
681 | ret = iucv_register(&vmlogrdr_iucv_handler, 1); | ||
682 | if (ret) { | ||
683 | printk (KERN_ERR "vmlogrdr: failed to register with" | ||
684 | "iucv driver\n"); | ||
685 | goto out; | ||
686 | } | ||
687 | |||
716 | ret = driver_register(&vmlogrdr_driver); | 688 | ret = driver_register(&vmlogrdr_driver); |
717 | if (ret) { | 689 | if (ret) { |
718 | printk(KERN_ERR "vmlogrdr: failed to register driver.\n"); | 690 | printk(KERN_ERR "vmlogrdr: failed to register driver.\n"); |
719 | return ret; | 691 | goto out_iucv; |
720 | } | 692 | } |
721 | 693 | ||
722 | ret = driver_create_file(&vmlogrdr_driver, | 694 | ret = driver_create_file(&vmlogrdr_driver, |
723 | &driver_attr_recording_status); | 695 | &driver_attr_recording_status); |
724 | if (ret) { | 696 | if (ret) { |
725 | printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n"); | 697 | printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n"); |
726 | goto unregdriver; | 698 | goto out_driver; |
727 | } | 699 | } |
728 | 700 | ||
729 | vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); | 701 | vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); |
730 | if (IS_ERR(vmlogrdr_class)) { | 702 | if (IS_ERR(vmlogrdr_class)) { |
731 | printk(KERN_ERR "vmlogrdr: failed to create class.\n"); | 703 | printk(KERN_ERR "vmlogrdr: failed to create class.\n"); |
732 | ret=PTR_ERR(vmlogrdr_class); | 704 | ret = PTR_ERR(vmlogrdr_class); |
733 | vmlogrdr_class=NULL; | 705 | vmlogrdr_class = NULL; |
734 | goto unregattr; | 706 | goto out_attr; |
735 | } | 707 | } |
736 | return 0; | 708 | return 0; |
737 | 709 | ||
738 | unregattr: | 710 | out_attr: |
739 | driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); | 711 | driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); |
740 | unregdriver: | 712 | out_driver: |
741 | driver_unregister(&vmlogrdr_driver); | 713 | driver_unregister(&vmlogrdr_driver); |
714 | out_iucv: | ||
715 | iucv_unregister(&vmlogrdr_iucv_handler, 1); | ||
716 | out: | ||
742 | return ret; | 717 | return ret; |
743 | } | 718 | } |
744 | 719 | ||
745 | 720 | ||
746 | static void | 721 | static void vmlogrdr_unregister_driver(void) |
747 | vmlogrdr_unregister_driver(void) { | 722 | { |
748 | class_destroy(vmlogrdr_class); | 723 | class_destroy(vmlogrdr_class); |
749 | vmlogrdr_class = NULL; | 724 | vmlogrdr_class = NULL; |
750 | driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); | 725 | driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); |
751 | driver_unregister(&vmlogrdr_driver); | 726 | driver_unregister(&vmlogrdr_driver); |
752 | return; | 727 | iucv_unregister(&vmlogrdr_iucv_handler, 1); |
753 | } | 728 | } |
754 | 729 | ||
755 | 730 | ||
756 | static int | 731 | static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) |
757 | vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { | 732 | { |
758 | struct device *dev; | 733 | struct device *dev; |
759 | int ret; | 734 | int ret; |
760 | 735 | ||
@@ -803,9 +778,10 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { | |||
803 | } | 778 | } |
804 | 779 | ||
805 | 780 | ||
806 | static int | 781 | static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv) |
807 | vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { | 782 | { |
808 | class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num)); | 783 | class_device_destroy(vmlogrdr_class, |
784 | MKDEV(vmlogrdr_major, priv->minor_num)); | ||
809 | if (priv->device != NULL) { | 785 | if (priv->device != NULL) { |
810 | sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); | 786 | sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); |
811 | device_unregister(priv->device); | 787 | device_unregister(priv->device); |
@@ -815,8 +791,8 @@ vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { | |||
815 | } | 791 | } |
816 | 792 | ||
817 | 793 | ||
818 | static int | 794 | static int vmlogrdr_register_cdev(dev_t dev) |
819 | vmlogrdr_register_cdev(dev_t dev) { | 795 | { |
820 | int rc = 0; | 796 | int rc = 0; |
821 | vmlogrdr_cdev = cdev_alloc(); | 797 | vmlogrdr_cdev = cdev_alloc(); |
822 | if (!vmlogrdr_cdev) { | 798 | if (!vmlogrdr_cdev) { |
@@ -836,9 +812,10 @@ vmlogrdr_register_cdev(dev_t dev) { | |||
836 | } | 812 | } |
837 | 813 | ||
838 | 814 | ||
839 | static void | 815 | static void vmlogrdr_cleanup(void) |
840 | vmlogrdr_cleanup(void) { | 816 | { |
841 | int i; | 817 | int i; |
818 | |||
842 | if (vmlogrdr_cdev) { | 819 | if (vmlogrdr_cdev) { |
843 | cdev_del(vmlogrdr_cdev); | 820 | cdev_del(vmlogrdr_cdev); |
844 | vmlogrdr_cdev=NULL; | 821 | vmlogrdr_cdev=NULL; |
@@ -855,8 +832,7 @@ vmlogrdr_cleanup(void) { | |||
855 | } | 832 | } |
856 | 833 | ||
857 | 834 | ||
858 | static int | 835 | static int vmlogrdr_init(void) |
859 | vmlogrdr_init(void) | ||
860 | { | 836 | { |
861 | int rc; | 837 | int rc; |
862 | int i; | 838 | int i; |
@@ -906,8 +882,7 @@ cleanup: | |||
906 | } | 882 | } |
907 | 883 | ||
908 | 884 | ||
909 | static void | 885 | static void vmlogrdr_exit(void) |
910 | vmlogrdr_exit(void) | ||
911 | { | 886 | { |
912 | vmlogrdr_cleanup(); | 887 | vmlogrdr_cleanup(); |
913 | printk (KERN_INFO "vmlogrdr: driver unloaded\n"); | 888 | printk (KERN_INFO "vmlogrdr: driver unloaded\n"); |