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