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