1 /*
2  *      Copyright (C) 1996, 1997 Claus-Justus Heine.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2, or (at your option)
7  any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; see the file COPYING.  If not, write to
16  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18  *
19  *      This file contains the code that registers the zftape frontend
20  *      to the ftape floppy tape driver for Linux
21  */
22 
23 #include <linux/config.h>
24 #include <linux/module.h>
25 #include <linux/errno.h>
26 #include <linux/version.h>
27 #include <linux/fs.h>
28 #include <asm/segment.h>
29 #include <linux/kernel.h>
30 #include <linux/signal.h>
31 #include <linux/major.h>
32 #include <linux/slab.h>
33 #ifdef CONFIG_KMOD
34 #include <linux/kmod.h>
35 #endif
36 #include <linux/fcntl.h>
37 #include <linux/wrapper.h>
38 #include <linux/smp_lock.h>
39 #include <linux/devfs_fs_kernel.h>
40 
41 #include <linux/zftape.h>
42 #include <linux/init.h>
43 
44 #include "../zftape/zftape-init.h"
45 #include "../zftape/zftape-read.h"
46 #include "../zftape/zftape-write.h"
47 #include "../zftape/zftape-ctl.h"
48 #include "../zftape/zftape-buffers.h"
49 #include "../zftape/zftape_syms.h"
50 
51 char zft_src[] __initdata = "$Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-init.c,v $";
52 char zft_rev[] __initdata = "$Revision: 1.8 $";
53 char zft_dat[] __initdata = "$Date: 1997/11/06 00:48:56 $";
54 
55 MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine "
56 	      "(claus@momo.math.rwth-aachen.de)");
57 MODULE_DESCRIPTION(ZFTAPE_VERSION " - "
58 		   "VFS interface for the Linux floppy tape driver. "
59 		   "Support for QIC-113 compatible volume table "
60 		   "and builtin compression (lzrw3 algorithm)");
61 MODULE_SUPPORTED_DEVICE("char-major-27");
62 MODULE_LICENSE("GPL");
63 
64 /*      Global vars.
65  */
66 struct zft_cmpr_ops *zft_cmpr_ops = NULL;
67 const ftape_info *zft_status;
68 
69 /*      Local vars.
70  */
71 static int busy_flag = 0;
72 static sigset_t orig_sigmask;
73 
74 /*  the interface to the kernel vfs layer
75  */
76 
77 /* Note about llseek():
78  *
79  * st.c and tpqic.c update fp->f_pos but don't implment llseek() and
80  * initialize the llseek component of the file_ops struct with NULL.
81  * This means that the user will get the default seek, but the tape
82  * device will not respect the new position, but happily read from the
83  * old position. Think a zftape specific llseek() function would be
84  * better, returning -ESPIPE. TODO.
85  */
86 
87 static int  zft_open (struct inode *ino, struct file *filep);
88 static int zft_close(struct inode *ino, struct file *filep);
89 static int  zft_ioctl(struct inode *ino, struct file *filep,
90 		      unsigned int command, unsigned long arg);
91 static int  zft_mmap(struct file *filep, struct vm_area_struct *vma);
92 static ssize_t zft_read (struct file *fp, char *buff,
93 			 size_t req_len, loff_t *ppos);
94 static ssize_t zft_write(struct file *fp, const char *buff,
95 			 size_t req_len, loff_t *ppos);
96 
97 static struct file_operations zft_cdev =
98 {
99 	owner:		THIS_MODULE,
100 	read:		zft_read,
101 	write:		zft_write,
102 	ioctl:		zft_ioctl,
103 	mmap:		zft_mmap,
104 	open:		zft_open,
105 	release:	zft_close,
106 };
107 
108 /*      Open floppy tape device
109  */
zft_open(struct inode * ino,struct file * filep)110 static int zft_open(struct inode *ino, struct file *filep)
111 {
112 	int result;
113 	TRACE_FUN(ft_t_flow);
114 
115 	TRACE(ft_t_flow, "called for minor %d", MINOR(ino->i_rdev));
116 	if (busy_flag) {
117 		TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy");
118 	}
119 	busy_flag = 1;
120 	if ((MINOR(ino->i_rdev) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND))
121 	     >
122 	    FTAPE_SEL_D) {
123 		busy_flag = 0;
124 		TRACE_ABORT(-ENXIO, ft_t_err, "failed: illegal unit nr");
125 	}
126 	orig_sigmask = current->blocked;
127 	sigfillset(&current->blocked);
128 	result = _zft_open(MINOR(ino->i_rdev), filep->f_flags & O_ACCMODE);
129 	if (result < 0) {
130 		current->blocked = orig_sigmask; /* restore mask */
131 		busy_flag = 0;
132 		TRACE_ABORT(result, ft_t_err, "_ftape_open failed");
133 	} else {
134 		/* Mask signals that will disturb proper operation of the
135 		 * program that is calling.
136 		 */
137 		current->blocked = orig_sigmask;
138 		sigaddsetmask (&current->blocked, _DO_BLOCK);
139 		TRACE_EXIT 0;
140 	}
141 }
142 
143 /*      Close floppy tape device
144  */
zft_close(struct inode * ino,struct file * filep)145 static int zft_close(struct inode *ino, struct file *filep)
146 {
147 	int result;
148 	TRACE_FUN(ft_t_flow);
149 
150 	lock_kernel();
151 	if (!busy_flag || MINOR(ino->i_rdev) != zft_unit) {
152 		TRACE(ft_t_err, "failed: not busy or wrong unit");
153 		unlock_kernel();
154 		TRACE_EXIT 0;
155 	}
156 	sigfillset(&current->blocked);
157 	result = _zft_close();
158 	if (result < 0) {
159 		TRACE(ft_t_err, "_zft_close failed");
160 	}
161 	current->blocked = orig_sigmask; /* restore before open state */
162 	busy_flag = 0;
163 	unlock_kernel();
164 	TRACE_EXIT 0;
165 }
166 
167 /*      Ioctl for floppy tape device
168  */
zft_ioctl(struct inode * ino,struct file * filep,unsigned int command,unsigned long arg)169 static int zft_ioctl(struct inode *ino, struct file *filep,
170 		     unsigned int command, unsigned long arg)
171 {
172 	int result = -EIO;
173 	sigset_t old_sigmask;
174 	TRACE_FUN(ft_t_flow);
175 
176 	if (!busy_flag || MINOR(ino->i_rdev) != zft_unit || ft_failure) {
177 		TRACE_ABORT(-EIO, ft_t_err,
178 			    "failed: not busy, failure or wrong unit");
179 	}
180 	old_sigmask = current->blocked; /* save mask */
181 	sigfillset(&current->blocked);
182 	/* This will work as long as sizeof(void *) == sizeof(long) */
183 	result = _zft_ioctl(command, (void *) arg);
184 	current->blocked = old_sigmask; /* restore mask */
185 	TRACE_EXIT result;
186 }
187 
188 /*      Ioctl for floppy tape device
189  */
zft_mmap(struct file * filep,struct vm_area_struct * vma)190 static int  zft_mmap(struct file *filep, struct vm_area_struct *vma)
191 {
192 	int result = -EIO;
193 	sigset_t old_sigmask;
194 	TRACE_FUN(ft_t_flow);
195 
196 	if (!busy_flag ||
197 	    MINOR(filep->f_dentry->d_inode->i_rdev) != zft_unit ||
198 	    ft_failure)
199 	{
200 		TRACE_ABORT(-EIO, ft_t_err,
201 			    "failed: not busy, failure or wrong unit");
202 	}
203 	old_sigmask = current->blocked; /* save mask */
204 	sigfillset(&current->blocked);
205 	lock_kernel();
206 	if ((result = ftape_mmap(vma)) >= 0) {
207 #ifndef MSYNC_BUG_WAS_FIXED
208 		static struct vm_operations_struct dummy = { NULL, };
209 		vma->vm_ops = &dummy;
210 #endif
211 	}
212 	unlock_kernel();
213 	current->blocked = old_sigmask; /* restore mask */
214 	TRACE_EXIT result;
215 }
216 
217 /*      Read from floppy tape device
218  */
zft_read(struct file * fp,char * buff,size_t req_len,loff_t * ppos)219 static ssize_t zft_read(struct file *fp, char *buff,
220 			size_t req_len, loff_t *ppos)
221 {
222 	int result = -EIO;
223 	sigset_t old_sigmask;
224 	struct inode *ino = fp->f_dentry->d_inode;
225 	TRACE_FUN(ft_t_flow);
226 
227 	TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len);
228 	if (!busy_flag || MINOR(ino->i_rdev) != zft_unit || ft_failure) {
229 		TRACE_ABORT(-EIO, ft_t_err,
230 			    "failed: not busy, failure or wrong unit");
231 	}
232 	old_sigmask = current->blocked; /* save mask */
233 	sigfillset(&current->blocked);
234 	result = _zft_read(buff, req_len);
235 	current->blocked = old_sigmask; /* restore mask */
236 	TRACE(ft_t_data_flow, "return with count: %d", result);
237 	TRACE_EXIT result;
238 }
239 
240 /*      Write to tape device
241  */
zft_write(struct file * fp,const char * buff,size_t req_len,loff_t * ppos)242 static ssize_t zft_write(struct file *fp, const char *buff,
243 			 size_t req_len, loff_t *ppos)
244 {
245 	int result = -EIO;
246 	sigset_t old_sigmask;
247 	struct inode *ino = fp->f_dentry->d_inode;
248 	TRACE_FUN(ft_t_flow);
249 
250 	TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len);
251 	if (!busy_flag || MINOR(ino->i_rdev) != zft_unit || ft_failure) {
252 		TRACE_ABORT(-EIO, ft_t_err,
253 			    "failed: not busy, failure or wrong unit");
254 	}
255 	old_sigmask = current->blocked; /* save mask */
256 	sigfillset(&current->blocked);
257 	result = _zft_write(buff, req_len);
258 	current->blocked = old_sigmask; /* restore mask */
259 	TRACE(ft_t_data_flow, "return with count: %d", result);
260 	TRACE_EXIT result;
261 }
262 
263 /*                    END OF VFS INTERFACE
264  *
265  *****************************************************************************/
266 
267 /*  driver/module initialization
268  */
269 
270 /*  the compression module has to call this function to hook into the zftape
271  *  code
272  */
zft_cmpr_register(struct zft_cmpr_ops * new_ops)273 int zft_cmpr_register(struct zft_cmpr_ops *new_ops)
274 {
275 	TRACE_FUN(ft_t_flow);
276 
277 	if (zft_cmpr_ops != NULL) {
278 		TRACE_EXIT -EBUSY;
279 	} else {
280 		zft_cmpr_ops = new_ops;
281 		TRACE_EXIT 0;
282 	}
283 }
284 
zft_cmpr_unregister(void)285 struct zft_cmpr_ops *zft_cmpr_unregister(void)
286 {
287 	struct zft_cmpr_ops *old_ops = zft_cmpr_ops;
288 	TRACE_FUN(ft_t_flow);
289 
290 	zft_cmpr_ops = NULL;
291 	TRACE_EXIT old_ops;
292 }
293 
294 /*  lock the zft-compressor() module.
295  */
zft_cmpr_lock(int try_to_load)296 int zft_cmpr_lock(int try_to_load)
297 {
298 	if (zft_cmpr_ops == NULL) {
299 #ifdef CONFIG_KMOD
300 		if (try_to_load) {
301 			request_module("zft-compressor");
302 			if (zft_cmpr_ops == NULL) {
303 				return -ENOSYS;
304 			}
305 		} else {
306 			return -ENOSYS;
307 		}
308 #else
309 		return -ENOSYS;
310 #endif
311 	}
312 	(*zft_cmpr_ops->lock)();
313 	return 0;
314 }
315 
316 #ifdef CONFIG_ZFT_COMPRESSOR
317 extern int zft_compressor_init(void);
318 #endif
319 
320 /*  Called by modules package when installing the driver or by kernel
321  *  during the initialization phase
322  */
zft_init(void)323 int __init zft_init(void)
324 {
325 	int i;
326 	TRACE_FUN(ft_t_flow);
327 
328 #ifdef MODULE
329 	printk(KERN_INFO ZFTAPE_VERSION "\n");
330         if (TRACE_LEVEL >= ft_t_info) {
331 		printk(
332 KERN_INFO
333 "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n"
334 KERN_INFO
335 "vfs interface for ftape floppy tape driver.\n"
336 KERN_INFO
337 "Support for QIC-113 compatible volume table, dynamic memory allocation\n"
338 KERN_INFO
339 "and builtin compression (lzrw3 algorithm).\n"
340 KERN_INFO
341 "Compiled for Linux version %s"
342 #ifdef MODVERSIONS
343 		       " with versioned symbols"
344 #endif
345 		       "\n", UTS_RELEASE);
346         }
347 #else /* !MODULE */
348 	/* print a short no-nonsense boot message */
349 	printk(KERN_INFO ZFTAPE_VERSION " for Linux " UTS_RELEASE "\n");
350 #endif /* MODULE */
351 	TRACE(ft_t_info, "zft_init @ 0x%p", zft_init);
352 	TRACE(ft_t_info,
353 	      "installing zftape VFS interface for ftape driver ...");
354 	TRACE_CATCH(devfs_register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),);
355 
356 	for (i = 0; i < 4; i++) {
357 		char devname[9];
358 
359 		sprintf (devname, "qft%i", i);
360 		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
361 			        QIC117_TAPE_MAJOR, i,
362 				S_IFCHR | S_IRUSR | S_IWUSR,
363 				&zft_cdev, NULL);
364 		sprintf (devname, "nqft%i", i);
365 		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
366 				QIC117_TAPE_MAJOR, i + 4,
367 				S_IFCHR | S_IRUSR | S_IWUSR,
368 				&zft_cdev, NULL);
369 		sprintf (devname, "zqft%i", i);
370 		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
371 				QIC117_TAPE_MAJOR, i + 16,
372 				S_IFCHR | S_IRUSR | S_IWUSR,
373 				&zft_cdev, NULL);
374 		sprintf (devname, "nzqft%i", i);
375 		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
376 				QIC117_TAPE_MAJOR, i + 20,
377 				S_IFCHR | S_IRUSR | S_IWUSR,
378 				&zft_cdev, NULL);
379 		sprintf (devname, "rawqft%i", i);
380 		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
381 				QIC117_TAPE_MAJOR, i + 32,
382 				S_IFCHR | S_IRUSR | S_IWUSR,
383 				&zft_cdev, NULL);
384 		sprintf (devname, "nrawqft%i", i);
385 		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
386 				QIC117_TAPE_MAJOR, i + 36,
387 				S_IFCHR | S_IRUSR | S_IWUSR,
388 				&zft_cdev, NULL);
389 	}
390 
391 #ifdef CONFIG_ZFT_COMPRESSOR
392 	(void)zft_compressor_init();
393 #endif
394 	zft_status = ftape_get_status(); /*  fetch global data of ftape
395 					  *  hardware driver
396 					  */
397 	TRACE_EXIT 0;
398 }
399 
400 
401 #ifdef MODULE
402 /* Called by modules package before trying to unload the module
403  */
can_unload(void)404 static int can_unload(void)
405 {
406 	return (GET_USE_COUNT(THIS_MODULE)||zft_dirty()||busy_flag)?-EBUSY:0;
407 }
408 /* Called by modules package when installing the driver
409  */
init_module(void)410 int init_module(void)
411 {
412 	if (!mod_member_present(&__this_module, can_unload)) {
413 		return -EBUSY;
414 	}
415 	__this_module.can_unload = can_unload;
416 	return zft_init();
417 }
418 
419 /* Called by modules package when removing the driver
420  */
cleanup_module(void)421 void cleanup_module(void)
422 {
423 	int i;
424 	char devname[9];
425 
426 	TRACE_FUN(ft_t_flow);
427 
428 	if (devfs_unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) {
429 		TRACE(ft_t_warn, "failed");
430 	} else {
431 		TRACE(ft_t_info, "successful");
432 	}
433         for (i = 0; i < 4; i++) {
434 		sprintf(devname, "qft%i", i);
435 		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i, DEVFS_SPECIAL_CHR, 0));
436 		sprintf(devname, "nqft%i", i);
437 		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 4, DEVFS_SPECIAL_CHR, 0));
438 		sprintf(devname, "zqft%i", i);
439 		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 16, DEVFS_SPECIAL_CHR, 0));
440 		sprintf(devname, "nzqft%i", i);
441 		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 20, DEVFS_SPECIAL_CHR, 0));
442 		sprintf(devname, "rawqft%i", i);
443 		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 32, DEVFS_SPECIAL_CHR, 0));
444 		sprintf(devname, "nrawqft%i", i);
445 		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 36, DEVFS_SPECIAL_CHR, 0));
446 	}
447 	zft_uninit_mem(); /* release remaining memory, if any */
448         printk(KERN_INFO "zftape successfully unloaded.\n");
449 	TRACE_EXIT;
450 }
451 
452 #endif /* MODULE */
453