Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
[pandora-kernel.git] / drivers / s390 / char / tape_char.c
1 /*
2  *  drivers/s390/char/tape_char.c
3  *    character device frontend for tape device driver
4  *
5  *  S390 and zSeries version
6  *    Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
7  *    Author(s): Carsten Otte <cotte@de.ibm.com>
8  *               Michael Holzheu <holzheu@de.ibm.com>
9  *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
10  *               Martin Schwidefsky <schwidefsky@de.ibm.com>
11  */
12
13 #include <linux/module.h>
14 #include <linux/types.h>
15 #include <linux/proc_fs.h>
16 #include <linux/mtio.h>
17
18 #include <asm/uaccess.h>
19
20 #define TAPE_DBF_AREA   tape_core_dbf
21
22 #include "tape.h"
23 #include "tape_std.h"
24 #include "tape_class.h"
25
26 #define PRINTK_HEADER "TAPE_CHAR: "
27
28 #define TAPECHAR_MAJOR          0       /* get dynamic major */
29
30 /*
31  * file operation structure for tape character frontend
32  */
33 static ssize_t tapechar_read(struct file *, char __user *, size_t, loff_t *);
34 static ssize_t tapechar_write(struct file *, const char __user *, size_t, loff_t *);
35 static int tapechar_open(struct inode *,struct file *);
36 static int tapechar_release(struct inode *,struct file *);
37 static int tapechar_ioctl(struct inode *, struct file *, unsigned int,
38                           unsigned long);
39 static long tapechar_compat_ioctl(struct file *, unsigned int,
40                           unsigned long);
41
42 static struct file_operations tape_fops =
43 {
44         .owner = THIS_MODULE,
45         .read = tapechar_read,
46         .write = tapechar_write,
47         .ioctl = tapechar_ioctl,
48         .compat_ioctl = tapechar_compat_ioctl,
49         .open = tapechar_open,
50         .release = tapechar_release,
51 };
52
53 static int tapechar_major = TAPECHAR_MAJOR;
54
55 /*
56  * This function is called for every new tapedevice
57  */
58 int
59 tapechar_setup_device(struct tape_device * device)
60 {
61         char    device_name[20];
62
63         sprintf(device_name, "ntibm%i", device->first_minor / 2);
64         device->nt = register_tape_dev(
65                 &device->cdev->dev,
66                 MKDEV(tapechar_major, device->first_minor),
67                 &tape_fops,
68                 device_name,
69                 "non-rewinding"
70         );
71         device_name[0] = 'r';
72         device->rt = register_tape_dev(
73                 &device->cdev->dev,
74                 MKDEV(tapechar_major, device->first_minor + 1),
75                 &tape_fops,
76                 device_name,
77                 "rewinding"
78         );
79
80         return 0;
81 }
82
83 void
84 tapechar_cleanup_device(struct tape_device *device)
85 {
86         unregister_tape_dev(device->rt);
87         device->rt = NULL;
88         unregister_tape_dev(device->nt);
89         device->nt = NULL;
90 }
91
92 /*
93  * Terminate write command (we write two TMs and skip backward over last)
94  * This ensures that the tape is always correctly terminated.
95  * When the user writes afterwards a new file, he will overwrite the
96  * second TM and therefore one TM will remain to separate the
97  * two files on the tape...
98  */
99 static inline void
100 tapechar_terminate_write(struct tape_device *device)
101 {
102         if (tape_mtop(device, MTWEOF, 1) == 0 &&
103             tape_mtop(device, MTWEOF, 1) == 0)
104                 tape_mtop(device, MTBSR, 1);
105 }
106
107 static inline int
108 tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
109 {
110         struct idal_buffer *new;
111
112         if (device->char_data.idal_buf != NULL &&
113             device->char_data.idal_buf->size == block_size)
114                 return 0;
115
116         if (block_size > MAX_BLOCKSIZE) {
117                 DBF_EVENT(3, "Invalid blocksize (%zd > %d)\n",
118                         block_size, MAX_BLOCKSIZE);
119                 PRINT_ERR("Invalid blocksize (%zd> %d)\n",
120                         block_size, MAX_BLOCKSIZE);
121                 return -EINVAL;
122         }
123
124         /* The current idal buffer is not correct. Allocate a new one. */
125         new = idal_buffer_alloc(block_size, 0);
126         if (new == NULL)
127                 return -ENOMEM;
128
129         if (device->char_data.idal_buf != NULL)
130                 idal_buffer_free(device->char_data.idal_buf);
131
132         device->char_data.idal_buf = new;
133
134         return 0;
135 }
136
137 /*
138  * Tape device read function
139  */
140 ssize_t
141 tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
142 {
143         struct tape_device *device;
144         struct tape_request *request;
145         size_t block_size;
146         int rc;
147
148         DBF_EVENT(6, "TCHAR:read\n");
149         device = (struct tape_device *) filp->private_data;
150
151         /*
152          * If the tape isn't terminated yet, do it now. And since we then
153          * are at the end of the tape there wouldn't be anything to read
154          * anyways. So we return immediatly.
155          */
156         if(device->required_tapemarks) {
157                 return tape_std_terminate_write(device);
158         }
159
160         /* Find out block size to use */
161         if (device->char_data.block_size != 0) {
162                 if (count < device->char_data.block_size) {
163                         DBF_EVENT(3, "TCHAR:read smaller than block "
164                                   "size was requested\n");
165                         return -EINVAL;
166                 }
167                 block_size = device->char_data.block_size;
168         } else {
169                 block_size = count;
170         }
171
172         rc = tapechar_check_idalbuffer(device, block_size);
173         if (rc)
174                 return rc;
175
176 #ifdef CONFIG_S390_TAPE_BLOCK
177         /* Changes position. */
178         device->blk_data.medium_changed = 1;
179 #endif
180
181         DBF_EVENT(6, "TCHAR:nbytes: %lx\n", block_size);
182         /* Let the discipline build the ccw chain. */
183         request = device->discipline->read_block(device, block_size);
184         if (IS_ERR(request))
185                 return PTR_ERR(request);
186         /* Execute it. */
187         rc = tape_do_io(device, request);
188         if (rc == 0) {
189                 rc = block_size - request->rescnt;
190                 DBF_EVENT(6, "TCHAR:rbytes:  %x\n", rc);
191                 filp->f_pos += rc;
192                 /* Copy data from idal buffer to user space. */
193                 if (idal_buffer_to_user(device->char_data.idal_buf,
194                                         data, rc) != 0)
195                         rc = -EFAULT;
196         }
197         tape_free_request(request);
198         return rc;
199 }
200
201 /*
202  * Tape device write function
203  */
204 ssize_t
205 tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos)
206 {
207         struct tape_device *device;
208         struct tape_request *request;
209         size_t block_size;
210         size_t written;
211         int nblocks;
212         int i, rc;
213
214         DBF_EVENT(6, "TCHAR:write\n");
215         device = (struct tape_device *) filp->private_data;
216         /* Find out block size and number of blocks */
217         if (device->char_data.block_size != 0) {
218                 if (count < device->char_data.block_size) {
219                         DBF_EVENT(3, "TCHAR:write smaller than block "
220                                   "size was requested\n");
221                         return -EINVAL;
222                 }
223                 block_size = device->char_data.block_size;
224                 nblocks = count / block_size;
225         } else {
226                 block_size = count;
227                 nblocks = 1;
228         }
229
230         rc = tapechar_check_idalbuffer(device, block_size);
231         if (rc)
232                 return rc;
233
234 #ifdef CONFIG_S390_TAPE_BLOCK
235         /* Changes position. */
236         device->blk_data.medium_changed = 1;
237 #endif
238
239         DBF_EVENT(6,"TCHAR:nbytes: %lx\n", block_size);
240         DBF_EVENT(6, "TCHAR:nblocks: %x\n", nblocks);
241         /* Let the discipline build the ccw chain. */
242         request = device->discipline->write_block(device, block_size);
243         if (IS_ERR(request))
244                 return PTR_ERR(request);
245         rc = 0;
246         written = 0;
247         for (i = 0; i < nblocks; i++) {
248                 /* Copy data from user space to idal buffer. */
249                 if (idal_buffer_from_user(device->char_data.idal_buf,
250                                           data, block_size)) {
251                         rc = -EFAULT;
252                         break;
253                 }
254                 rc = tape_do_io(device, request);
255                 if (rc)
256                         break;
257                 DBF_EVENT(6, "TCHAR:wbytes: %lx\n",
258                           block_size - request->rescnt);
259                 filp->f_pos += block_size - request->rescnt;
260                 written += block_size - request->rescnt;
261                 if (request->rescnt != 0)
262                         break;
263                 data += block_size;
264         }
265         tape_free_request(request);
266         if (rc == -ENOSPC) {
267                 /*
268                  * Ok, the device has no more space. It has NOT written
269                  * the block.
270                  */
271                 if (device->discipline->process_eov)
272                         device->discipline->process_eov(device);
273                 if (written > 0)
274                         rc = 0;
275
276         }
277
278         /*
279          * After doing a write we always need two tapemarks to correctly
280          * terminate the tape (one to terminate the file, the second to
281          * flag the end of recorded data.
282          * Since process_eov positions the tape in front of the written
283          * tapemark it doesn't hurt to write two marks again.
284          */
285         if (!rc)
286                 device->required_tapemarks = 2;
287
288         return rc ? rc : written;
289 }
290
291 /*
292  * Character frontend tape device open function.
293  */
294 int
295 tapechar_open (struct inode *inode, struct file *filp)
296 {
297         struct tape_device *device;
298         int minor, rc;
299
300         DBF_EVENT(6, "TCHAR:open: %i:%i\n",
301                 imajor(filp->f_path.dentry->d_inode),
302                 iminor(filp->f_path.dentry->d_inode));
303
304         if (imajor(filp->f_path.dentry->d_inode) != tapechar_major)
305                 return -ENODEV;
306
307         minor = iminor(filp->f_path.dentry->d_inode);
308         device = tape_get_device(minor / TAPE_MINORS_PER_DEV);
309         if (IS_ERR(device)) {
310                 DBF_EVENT(3, "TCHAR:open: tape_get_device() failed\n");
311                 return PTR_ERR(device);
312         }
313
314
315         rc = tape_open(device);
316         if (rc == 0) {
317                 filp->private_data = device;
318                 return nonseekable_open(inode, filp);
319         }
320         tape_put_device(device);
321
322         return rc;
323 }
324
325 /*
326  * Character frontend tape device release function.
327  */
328
329 int
330 tapechar_release(struct inode *inode, struct file *filp)
331 {
332         struct tape_device *device;
333
334         DBF_EVENT(6, "TCHAR:release: %x\n", iminor(inode));
335         device = (struct tape_device *) filp->private_data;
336
337         /*
338          * If this is the rewinding tape minor then rewind. In that case we
339          * write all required tapemarks. Otherwise only one to terminate the
340          * file.
341          */
342         if ((iminor(inode) & 1) != 0) {
343                 if (device->required_tapemarks)
344                         tape_std_terminate_write(device);
345                 tape_mtop(device, MTREW, 1);
346         } else {
347                 if (device->required_tapemarks > 1) {
348                         if (tape_mtop(device, MTWEOF, 1) == 0)
349                                 device->required_tapemarks--;
350                 }
351         }
352
353         if (device->char_data.idal_buf != NULL) {
354                 idal_buffer_free(device->char_data.idal_buf);
355                 device->char_data.idal_buf = NULL;
356         }
357         tape_release(device);
358         filp->private_data = tape_put_device(device);
359
360         return 0;
361 }
362
363 /*
364  * Tape device io controls.
365  */
366 static int
367 tapechar_ioctl(struct inode *inp, struct file *filp,
368                unsigned int no, unsigned long data)
369 {
370         struct tape_device *device;
371         int rc;
372
373         DBF_EVENT(6, "TCHAR:ioct\n");
374
375         device = (struct tape_device *) filp->private_data;
376
377         if (no == MTIOCTOP) {
378                 struct mtop op;
379
380                 if (copy_from_user(&op, (char __user *) data, sizeof(op)) != 0)
381                         return -EFAULT;
382                 if (op.mt_count < 0)
383                         return -EINVAL;
384
385                 /*
386                  * Operations that change tape position should write final
387                  * tapemarks.
388                  */
389                 switch (op.mt_op) {
390                         case MTFSF:
391                         case MTBSF:
392                         case MTFSR:
393                         case MTBSR:
394                         case MTREW:
395                         case MTOFFL:
396                         case MTEOM:
397                         case MTRETEN:
398                         case MTBSFM:
399                         case MTFSFM:
400                         case MTSEEK:
401 #ifdef CONFIG_S390_TAPE_BLOCK
402                                 device->blk_data.medium_changed = 1;
403 #endif
404                                 if (device->required_tapemarks)
405                                         tape_std_terminate_write(device);
406                         default:
407                                 ;
408                 }
409                 rc = tape_mtop(device, op.mt_op, op.mt_count);
410
411                 if (op.mt_op == MTWEOF && rc == 0) {
412                         if (op.mt_count > device->required_tapemarks)
413                                 device->required_tapemarks = 0;
414                         else
415                                 device->required_tapemarks -= op.mt_count;
416                 }
417                 return rc;
418         }
419         if (no == MTIOCPOS) {
420                 /* MTIOCPOS: query the tape position. */
421                 struct mtpos pos;
422
423                 rc = tape_mtop(device, MTTELL, 1);
424                 if (rc < 0)
425                         return rc;
426                 pos.mt_blkno = rc;
427                 if (copy_to_user((char __user *) data, &pos, sizeof(pos)) != 0)
428                         return -EFAULT;
429                 return 0;
430         }
431         if (no == MTIOCGET) {
432                 /* MTIOCGET: query the tape drive status. */
433                 struct mtget get;
434
435                 memset(&get, 0, sizeof(get));
436                 get.mt_type = MT_ISUNKNOWN;
437                 get.mt_resid = 0 /* device->devstat.rescnt */;
438                 get.mt_dsreg = device->tape_state;
439                 /* FIXME: mt_gstat, mt_erreg, mt_fileno */
440                 get.mt_gstat = 0;
441                 get.mt_erreg = 0;
442                 get.mt_fileno = 0;
443                 get.mt_gstat  = device->tape_generic_status;
444
445                 if (device->medium_state == MS_LOADED) {
446                         rc = tape_mtop(device, MTTELL, 1);
447
448                         if (rc < 0)
449                                 return rc;
450
451                         if (rc == 0)
452                                 get.mt_gstat |= GMT_BOT(~0);
453
454                         get.mt_blkno = rc;
455                 }
456
457                 if (copy_to_user((char __user *) data, &get, sizeof(get)) != 0)
458                         return -EFAULT;
459
460                 return 0;
461         }
462         /* Try the discipline ioctl function. */
463         if (device->discipline->ioctl_fn == NULL)
464                 return -EINVAL;
465         return device->discipline->ioctl_fn(device, no, data);
466 }
467
468 static long
469 tapechar_compat_ioctl(struct file *filp, unsigned int no, unsigned long data)
470 {
471         struct tape_device *device = filp->private_data;
472         int rval = -ENOIOCTLCMD;
473
474         if (device->discipline->ioctl_fn) {
475                 lock_kernel();
476                 rval = device->discipline->ioctl_fn(device, no, data);
477                 unlock_kernel();
478                 if (rval == -EINVAL)
479                         rval = -ENOIOCTLCMD;
480         }
481
482         return rval;
483 }
484
485 /*
486  * Initialize character device frontend.
487  */
488 int
489 tapechar_init (void)
490 {
491         dev_t   dev;
492
493         if (alloc_chrdev_region(&dev, 0, 256, "tape") != 0)
494                 return -1;
495
496         tapechar_major = MAJOR(dev);
497         PRINT_INFO("tape gets major %d for character devices\n", MAJOR(dev));
498
499         return 0;
500 }
501
502 /*
503  * cleanup
504  */
505 void
506 tapechar_exit(void)
507 {
508         PRINT_INFO("tape releases major %d for character devices\n",
509                 tapechar_major);
510         unregister_chrdev_region(MKDEV(tapechar_major, 0), 256);
511 }