[S390] rename NT_PRXSTATUS to NT_S390_HIGHREGS
[linux-2.6-block.git] / drivers / s390 / char / tape_char.c
CommitLineData
1da177e4
LT
1/*
2 * drivers/s390/char/tape_char.c
3 * character device frontend for tape device driver
4 *
5 * S390 and zSeries version
cced1dd4 6 * Copyright IBM Corp. 2001,2006
1da177e4
LT
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
1da177e4
LT
13#include <linux/module.h>
14#include <linux/types.h>
15#include <linux/proc_fs.h>
16#include <linux/mtio.h>
764a4a8e 17#include <linux/smp_lock.h>
1da177e4
LT
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
1da177e4
LT
27#define TAPECHAR_MAJOR 0 /* get dynamic major */
28
29/*
30 * file operation structure for tape character frontend
31 */
32static ssize_t tapechar_read(struct file *, char __user *, size_t, loff_t *);
33static ssize_t tapechar_write(struct file *, const char __user *, size_t, loff_t *);
34static int tapechar_open(struct inode *,struct file *);
35static int tapechar_release(struct inode *,struct file *);
369a4632 36static long tapechar_ioctl(struct file *, unsigned int, unsigned long);
f042e0f8
CH
37static long tapechar_compat_ioctl(struct file *, unsigned int,
38 unsigned long);
1da177e4 39
d54b1fdb 40static const struct file_operations tape_fops =
1da177e4
LT
41{
42 .owner = THIS_MODULE,
43 .read = tapechar_read,
44 .write = tapechar_write,
369a4632 45 .unlocked_ioctl = tapechar_ioctl,
f042e0f8 46 .compat_ioctl = tapechar_compat_ioctl,
1da177e4
LT
47 .open = tapechar_open,
48 .release = tapechar_release,
49};
50
51static int tapechar_major = TAPECHAR_MAJOR;
52
53/*
54 * This function is called for every new tapedevice
55 */
56int
57tapechar_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
81void
82tapechar_cleanup_device(struct tape_device *device)
83{
92bf435f 84 unregister_tape_dev(&device->cdev->dev, device->rt);
1da177e4 85 device->rt = NULL;
92bf435f 86 unregister_tape_dev(&device->cdev->dev, device->nt);
1da177e4
LT
87 device->nt = NULL;
88}
89
4d284cac 90static int
1da177e4
LT
91tapechar_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);
1da177e4
LT
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);
0983e568 107 if (IS_ERR(new))
1da177e4
LT
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 */
2b67fc46 121static ssize_t
1da177e4
LT
122tapechar_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);
1da177e4
LT
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 */
2b67fc46 184static ssize_t
1da177e4
LT
185tapechar_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);
1da177e4
LT
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 */
2b67fc46 273static int
1da177e4
LT
274tapechar_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",
49522c97
JS
280 imajor(filp->f_path.dentry->d_inode),
281 iminor(filp->f_path.dentry->d_inode));
1da177e4 282
49522c97 283 if (imajor(filp->f_path.dentry->d_inode) != tapechar_major)
1da177e4
LT
284 return -ENODEV;
285
49522c97 286 minor = iminor(filp->f_path.dentry->d_inode);
8fd138c3 287 device = tape_find_device(minor / TAPE_MINORS_PER_DEV);
1da177e4 288 if (IS_ERR(device)) {
8fd138c3 289 DBF_EVENT(3, "TCHAR:open: tape_find_device() failed\n");
369a4632 290 return PTR_ERR(device);
1da177e4
LT
291 }
292
1da177e4
LT
293 rc = tape_open(device);
294 if (rc == 0) {
295 filp->private_data = device;
369a4632
MS
296 nonseekable_open(inode, filp);
297 } else
764a4a8e 298 tape_put_device(device);
1da177e4
LT
299
300 return rc;
301}
302
303/*
304 * Character frontend tape device release function.
305 */
306
2b67fc46 307static int
1da177e4
LT
308tapechar_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);
8fd138c3
MS
336 filp->private_data = NULL;
337 tape_put_device(device);
1da177e4
LT
338
339 return 0;
340}
341
342/*
343 * Tape device io controls.
344 */
345static int
369a4632
MS
346__tapechar_ioctl(struct tape_device *device,
347 unsigned int no, unsigned long data)
1da177e4 348{
1da177e4
LT
349 int rc;
350
1da177e4
LT
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
369a4632
MS
442static long
443tapechar_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
f042e0f8
CH
457static long
458tapechar_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) {
369a4632 464 mutex_lock(&device->mutex);
f042e0f8 465 rval = device->discipline->ioctl_fn(device, no, data);
369a4632 466 mutex_unlock(&device->mutex);
f042e0f8
CH
467 if (rval == -EINVAL)
468 rval = -ENOIOCTLCMD;
469 }
470
471 return rval;
472}
473
1da177e4
LT
474/*
475 * Initialize character device frontend.
476 */
477int
478tapechar_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);
1da177e4
LT
486
487 return 0;
488}
489
490/*
491 * cleanup
492 */
493void
494tapechar_exit(void)
495{
1da177e4
LT
496 unregister_chrdev_region(MKDEV(tapechar_major, 0), 256);
497}