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