diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/char/ftape/zftape |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/char/ftape/zftape')
-rw-r--r-- | drivers/char/ftape/zftape/Makefile | 36 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-buffers.c | 149 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-buffers.h | 55 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-ctl.c | 1418 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-ctl.h | 59 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-eof.c | 199 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-eof.h | 52 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-init.c | 403 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-init.h | 77 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-read.c | 377 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-read.h | 53 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-rw.c | 376 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-rw.h | 102 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-vtbl.c | 757 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-vtbl.h | 227 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-write.c | 483 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape-write.h | 38 | ||||
-rw-r--r-- | drivers/char/ftape/zftape/zftape_syms.c | 43 |
18 files changed, 4904 insertions, 0 deletions
diff --git a/drivers/char/ftape/zftape/Makefile b/drivers/char/ftape/zftape/Makefile new file mode 100644 index 000000000000..6d91c1f77c05 --- /dev/null +++ b/drivers/char/ftape/zftape/Makefile | |||
@@ -0,0 +1,36 @@ | |||
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 | # $Source: /homes/cvs/ftape-stacked/ftape/zftape/Makefile,v $ | ||
19 | # $Revision: 1.4 $ | ||
20 | # $Date: 1997/10/05 19:18:58 $ | ||
21 | # | ||
22 | # Makefile for the QIC-40/80/3010/3020 zftape interface VFS to | ||
23 | # ftape | ||
24 | # | ||
25 | |||
26 | |||
27 | # ZFT_OBSOLETE - enable the MTIOC_ZFTAPE_GETBLKSZ ioctl. You should | ||
28 | # leave this enabled for compatibility with taper. | ||
29 | |||
30 | obj-$(CONFIG_ZFTAPE) += zftape.o | ||
31 | |||
32 | zftape-objs := zftape-rw.o zftape-ctl.o zftape-read.o \ | ||
33 | zftape-write.o zftape-vtbl.o zftape-eof.o \ | ||
34 | zftape-init.o zftape-buffers.o zftape_syms.o | ||
35 | |||
36 | EXTRA_CFLAGS := -DZFT_OBSOLETE | ||
diff --git a/drivers/char/ftape/zftape/zftape-buffers.c b/drivers/char/ftape/zftape/zftape-buffers.c new file mode 100644 index 000000000000..da06f138334e --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-buffers.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1995-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 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-buffers.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:18:59 $ | ||
22 | * | ||
23 | * This file contains the dynamic buffer allocation routines | ||
24 | * of zftape | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/delay.h> | ||
31 | |||
32 | #include <linux/zftape.h> | ||
33 | |||
34 | #include <linux/vmalloc.h> | ||
35 | |||
36 | #include "../zftape/zftape-init.h" | ||
37 | #include "../zftape/zftape-eof.h" | ||
38 | #include "../zftape/zftape-ctl.h" | ||
39 | #include "../zftape/zftape-write.h" | ||
40 | #include "../zftape/zftape-read.h" | ||
41 | #include "../zftape/zftape-rw.h" | ||
42 | #include "../zftape/zftape-vtbl.h" | ||
43 | |||
44 | /* global variables | ||
45 | */ | ||
46 | |||
47 | /* local varibales | ||
48 | */ | ||
49 | static unsigned int used_memory; | ||
50 | static unsigned int peak_memory; | ||
51 | |||
52 | void zft_memory_stats(void) | ||
53 | { | ||
54 | TRACE_FUN(ft_t_flow); | ||
55 | |||
56 | TRACE(ft_t_noise, "Memory usage (vmalloc allocations):\n" | ||
57 | KERN_INFO "total allocated: %d\n" | ||
58 | KERN_INFO "peak allocation: %d", | ||
59 | used_memory, peak_memory); | ||
60 | peak_memory = used_memory; | ||
61 | TRACE_EXIT; | ||
62 | } | ||
63 | |||
64 | int zft_vcalloc_once(void *new, size_t size) | ||
65 | { | ||
66 | TRACE_FUN(ft_t_flow); | ||
67 | if (zft_vmalloc_once(new, size) < 0) { | ||
68 | TRACE_EXIT -ENOMEM; | ||
69 | } | ||
70 | memset(*(void **)new, '\0', size); | ||
71 | TRACE_EXIT 0; | ||
72 | } | ||
73 | int zft_vmalloc_once(void *new, size_t size) | ||
74 | { | ||
75 | TRACE_FUN(ft_t_flow); | ||
76 | |||
77 | if (*(void **)new != NULL || size == 0) { | ||
78 | TRACE_EXIT 0; | ||
79 | } | ||
80 | if ((*(void **)new = vmalloc(size)) == NULL) { | ||
81 | TRACE_EXIT -ENOMEM; | ||
82 | } | ||
83 | used_memory += size; | ||
84 | if (peak_memory < used_memory) { | ||
85 | peak_memory = used_memory; | ||
86 | } | ||
87 | TRACE_ABORT(0, ft_t_noise, | ||
88 | "allocated buffer @ %p, %d bytes", *(void **)new, size); | ||
89 | } | ||
90 | int zft_vmalloc_always(void *new, size_t size) | ||
91 | { | ||
92 | TRACE_FUN(ft_t_flow); | ||
93 | |||
94 | zft_vfree(new, size); | ||
95 | TRACE_EXIT zft_vmalloc_once(new, size); | ||
96 | } | ||
97 | void zft_vfree(void *old, size_t size) | ||
98 | { | ||
99 | TRACE_FUN(ft_t_flow); | ||
100 | |||
101 | if (*(void **)old) { | ||
102 | vfree(*(void **)old); | ||
103 | used_memory -= size; | ||
104 | TRACE(ft_t_noise, "released buffer @ %p, %d bytes", | ||
105 | *(void **)old, size); | ||
106 | *(void **)old = NULL; | ||
107 | } | ||
108 | TRACE_EXIT; | ||
109 | } | ||
110 | |||
111 | void *zft_kmalloc(size_t size) | ||
112 | { | ||
113 | void *new; | ||
114 | |||
115 | while ((new = kmalloc(size, GFP_KERNEL)) == NULL) { | ||
116 | msleep_interruptible(100); | ||
117 | } | ||
118 | memset(new, 0, size); | ||
119 | used_memory += size; | ||
120 | if (peak_memory < used_memory) { | ||
121 | peak_memory = used_memory; | ||
122 | } | ||
123 | return new; | ||
124 | } | ||
125 | |||
126 | void zft_kfree(void *old, size_t size) | ||
127 | { | ||
128 | kfree(old); | ||
129 | used_memory -= size; | ||
130 | } | ||
131 | |||
132 | /* there are some more buffers that are allocated on demand. | ||
133 | * cleanup_module() calles this function to be sure to have released | ||
134 | * them | ||
135 | */ | ||
136 | void zft_uninit_mem(void) | ||
137 | { | ||
138 | TRACE_FUN(ft_t_flow); | ||
139 | |||
140 | zft_vfree(&zft_hseg_buf, FT_SEGMENT_SIZE); | ||
141 | zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); zft_deblock_segment = -1; | ||
142 | zft_free_vtbl(); | ||
143 | if (zft_cmpr_lock(0 /* don't load */) == 0) { | ||
144 | (*zft_cmpr_ops->cleanup)(); | ||
145 | (*zft_cmpr_ops->reset)(); /* unlock it again */ | ||
146 | } | ||
147 | zft_memory_stats(); | ||
148 | TRACE_EXIT; | ||
149 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-buffers.h b/drivers/char/ftape/zftape/zftape-buffers.h new file mode 100644 index 000000000000..798e3128c682 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-buffers.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef _FTAPE_DYNMEM_H | ||
2 | #define _FTAPE_DYNMEM_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1995-1997 Claus-Justus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-buffers.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:18:59 $ | ||
25 | * | ||
26 | * memory allocation routines. | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | /* we do not allocate all of the really large buffer memory before | ||
31 | * someone tries to open the drive. ftape_open() may fail with | ||
32 | * -ENOMEM, but that's better having 200k of vmalloced memory which | ||
33 | * cannot be swapped out. | ||
34 | */ | ||
35 | |||
36 | extern void zft_memory_stats(void); | ||
37 | extern int zft_vmalloc_once(void *new, size_t size); | ||
38 | extern int zft_vcalloc_once(void *new, size_t size); | ||
39 | extern int zft_vmalloc_always(void *new, size_t size); | ||
40 | extern void zft_vfree(void *old, size_t size); | ||
41 | extern void *zft_kmalloc(size_t size); | ||
42 | extern void zft_kfree(void *old, size_t size); | ||
43 | |||
44 | /* called by cleanup_module() | ||
45 | */ | ||
46 | extern void zft_uninit_mem(void); | ||
47 | |||
48 | #endif | ||
49 | |||
50 | |||
51 | |||
52 | |||
53 | |||
54 | |||
55 | |||
diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c new file mode 100644 index 000000000000..6c7874e5c199 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-ctl.c | |||
@@ -0,0 +1,1418 @@ | |||
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 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-ctl.c,v $ | ||
20 | * $Revision: 1.2.6.2 $ | ||
21 | * $Date: 1997/11/14 18:07:33 $ | ||
22 | * | ||
23 | * This file contains the non-read/write zftape functions | ||
24 | * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. | ||
25 | */ | ||
26 | |||
27 | #include <linux/config.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/fcntl.h> | ||
32 | |||
33 | #include <linux/zftape.h> | ||
34 | |||
35 | #include <asm/uaccess.h> | ||
36 | |||
37 | #include "../zftape/zftape-init.h" | ||
38 | #include "../zftape/zftape-eof.h" | ||
39 | #include "../zftape/zftape-ctl.h" | ||
40 | #include "../zftape/zftape-write.h" | ||
41 | #include "../zftape/zftape-read.h" | ||
42 | #include "../zftape/zftape-rw.h" | ||
43 | #include "../zftape/zftape-vtbl.h" | ||
44 | |||
45 | /* Global vars. | ||
46 | */ | ||
47 | int zft_write_protected; /* this is when cartridge rdonly or O_RDONLY */ | ||
48 | int zft_header_read; | ||
49 | int zft_offline; | ||
50 | unsigned int zft_unit; | ||
51 | int zft_resid; | ||
52 | int zft_mt_compression; | ||
53 | |||
54 | /* Local vars. | ||
55 | */ | ||
56 | static int going_offline; | ||
57 | |||
58 | typedef int (mt_fun)(int *argptr); | ||
59 | typedef int (*mt_funp)(int *argptr); | ||
60 | typedef struct | ||
61 | { | ||
62 | mt_funp function; | ||
63 | unsigned offline : 1; /* op permitted if offline or no_tape */ | ||
64 | unsigned write_protected : 1; /* op permitted if write-protected */ | ||
65 | unsigned not_formatted : 1; /* op permitted if tape not formatted */ | ||
66 | unsigned raw_mode : 1; /* op permitted if zft_mode == 0 */ | ||
67 | unsigned need_idle_state : 1; /* need to call def_idle_state */ | ||
68 | char *name; | ||
69 | } fun_entry; | ||
70 | |||
71 | static mt_fun mt_dummy, mt_reset, mt_fsr, mt_bsr, mt_rew, mt_offl, mt_nop, | ||
72 | mt_weof, mt_erase, mt_ras2, mt_setblk, mt_setdensity, | ||
73 | mt_seek, mt_tell, mt_reten, mt_eom, mt_fsf, mt_bsf, | ||
74 | mt_fsfm, mt_bsfm, mt_setdrvbuffer, mt_compression; | ||
75 | |||
76 | static fun_entry mt_funs[]= | ||
77 | { | ||
78 | {mt_reset , 1, 1, 1, 1, 0, "MT_RESET" }, /* 0 */ | ||
79 | {mt_fsf , 0, 1, 0, 0, 1, "MT_FSF" }, | ||
80 | {mt_bsf , 0, 1, 0, 0, 1, "MT_BSF" }, | ||
81 | {mt_fsr , 0, 1, 0, 1, 1, "MT_FSR" }, | ||
82 | {mt_bsr , 0, 1, 0, 1, 1, "MT_BSR" }, | ||
83 | {mt_weof , 0, 0, 0, 0, 0, "MT_WEOF" }, /* 5 */ | ||
84 | {mt_rew , 0, 1, 1, 1, 0, "MT_REW" }, | ||
85 | {mt_offl , 0, 1, 1, 1, 0, "MT_OFFL" }, | ||
86 | {mt_nop , 1, 1, 1, 1, 0, "MT_NOP" }, | ||
87 | {mt_reten , 0, 1, 1, 1, 0, "MT_RETEN" }, | ||
88 | {mt_bsfm , 0, 1, 0, 0, 1, "MT_BSFM" }, /* 10 */ | ||
89 | {mt_fsfm , 0, 1, 0, 0, 1, "MT_FSFM" }, | ||
90 | {mt_eom , 0, 1, 0, 0, 1, "MT_EOM" }, | ||
91 | {mt_erase , 0, 0, 0, 1, 0, "MT_ERASE" }, | ||
92 | {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS1" }, | ||
93 | {mt_ras2 , 0, 0, 0, 1, 0, "MT_RAS2" }, | ||
94 | {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS3" }, | ||
95 | {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, | ||
96 | {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, | ||
97 | {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, | ||
98 | {mt_setblk , 1, 1, 1, 1, 1, "MT_SETBLK"}, /* 20 */ | ||
99 | {mt_setdensity , 1, 1, 1, 1, 0, "MT_SETDENSITY"}, | ||
100 | {mt_seek , 0, 1, 0, 1, 1, "MT_SEEK" }, | ||
101 | {mt_dummy , 0, 1, 0, 1, 1, "MT_TELL" }, /* wr-only ?! */ | ||
102 | {mt_setdrvbuffer, 1, 1, 1, 1, 0, "MT_SETDRVBUFFER" }, | ||
103 | {mt_dummy , 1, 1, 1, 1, 0, "MT_FSS" }, /* 25 */ | ||
104 | {mt_dummy , 1, 1, 1, 1, 0, "MT_BSS" }, | ||
105 | {mt_dummy , 1, 1, 1, 1, 0, "MT_WSM" }, | ||
106 | {mt_dummy , 1, 1, 1, 1, 0, "MT_LOCK" }, | ||
107 | {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOCK"}, | ||
108 | {mt_dummy , 1, 1, 1, 1, 0, "MT_LOAD" }, /* 30 */ | ||
109 | {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOAD"}, | ||
110 | {mt_compression , 1, 1, 1, 0, 1, "MT_COMPRESSION"}, | ||
111 | {mt_dummy , 1, 1, 1, 1, 0, "MT_SETPART"}, | ||
112 | {mt_dummy , 1, 1, 1, 1, 0, "MT_MKPART"} | ||
113 | }; | ||
114 | |||
115 | #define NR_MT_CMDS NR_ITEMS(mt_funs) | ||
116 | |||
117 | void zft_reset_position(zft_position *pos) | ||
118 | { | ||
119 | TRACE_FUN(ft_t_flow); | ||
120 | |||
121 | pos->seg_byte_pos = | ||
122 | pos->volume_pos = 0; | ||
123 | if (zft_header_read) { | ||
124 | /* need to keep track of the volume table and | ||
125 | * compression map. We therefor simply | ||
126 | * position at the beginning of the first | ||
127 | * volume. This covers old ftape archives as | ||
128 | * well has various flavours of the | ||
129 | * compression map segments. The worst case is | ||
130 | * that the compression map shows up as a | ||
131 | * additional volume in front of all others. | ||
132 | */ | ||
133 | pos->seg_pos = zft_find_volume(0)->start_seg; | ||
134 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
135 | } else { | ||
136 | pos->tape_pos = 0; | ||
137 | pos->seg_pos = -1; | ||
138 | } | ||
139 | zft_just_before_eof = 0; | ||
140 | zft_deblock_segment = -1; | ||
141 | zft_io_state = zft_idle; | ||
142 | zft_zap_read_buffers(); | ||
143 | zft_prevent_flush(); | ||
144 | /* unlock the compresison module if it is loaded. | ||
145 | * The zero arg means not to try to load the module. | ||
146 | */ | ||
147 | if (zft_cmpr_lock(0) == 0) { | ||
148 | (*zft_cmpr_ops->reset)(); /* unlock */ | ||
149 | } | ||
150 | TRACE_EXIT; | ||
151 | } | ||
152 | |||
153 | static void zft_init_driver(void) | ||
154 | { | ||
155 | TRACE_FUN(ft_t_flow); | ||
156 | |||
157 | zft_resid = | ||
158 | zft_header_read = | ||
159 | zft_old_ftape = | ||
160 | zft_offline = | ||
161 | zft_write_protected = | ||
162 | going_offline = | ||
163 | zft_mt_compression = | ||
164 | zft_header_changed = | ||
165 | zft_volume_table_changed = | ||
166 | zft_written_segments = 0; | ||
167 | zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; | ||
168 | zft_reset_position(&zft_pos); /* does most of the stuff */ | ||
169 | ftape_zap_read_buffers(); | ||
170 | ftape_set_state(idle); | ||
171 | TRACE_EXIT; | ||
172 | } | ||
173 | |||
174 | int zft_def_idle_state(void) | ||
175 | { | ||
176 | int result = 0; | ||
177 | TRACE_FUN(ft_t_flow); | ||
178 | |||
179 | if (!zft_header_read) { | ||
180 | result = zft_read_header_segments(); | ||
181 | } else if ((result = zft_flush_buffers()) >= 0 && zft_qic_mode) { | ||
182 | /* don't move past eof | ||
183 | */ | ||
184 | (void)zft_close_volume(&zft_pos); | ||
185 | } | ||
186 | if (ftape_abort_operation() < 0) { | ||
187 | TRACE(ft_t_warn, "ftape_abort_operation() failed"); | ||
188 | result = -EIO; | ||
189 | } | ||
190 | /* clear remaining read buffers */ | ||
191 | zft_zap_read_buffers(); | ||
192 | zft_io_state = zft_idle; | ||
193 | TRACE_EXIT result; | ||
194 | } | ||
195 | |||
196 | /***************************************************************************** | ||
197 | * * | ||
198 | * functions for the MTIOCTOP commands * | ||
199 | * * | ||
200 | *****************************************************************************/ | ||
201 | |||
202 | static int mt_dummy(int *dummy) | ||
203 | { | ||
204 | TRACE_FUN(ft_t_flow); | ||
205 | |||
206 | TRACE_EXIT -ENOSYS; | ||
207 | } | ||
208 | |||
209 | static int mt_reset(int *dummy) | ||
210 | { | ||
211 | TRACE_FUN(ft_t_flow); | ||
212 | |||
213 | (void)ftape_seek_to_bot(); | ||
214 | TRACE_CATCH(ftape_reset_drive(), | ||
215 | zft_init_driver(); zft_uninit_mem(); zft_offline = 1); | ||
216 | /* fake a re-open of the device. This will set all flage and | ||
217 | * allocate buffers as appropriate. The new tape condition will | ||
218 | * force the open routine to do anything we need. | ||
219 | */ | ||
220 | TRACE_CATCH(_zft_open(-1 /* fake reopen */, 0 /* dummy */),); | ||
221 | TRACE_EXIT 0; | ||
222 | } | ||
223 | |||
224 | static int mt_fsf(int *arg) | ||
225 | { | ||
226 | int result; | ||
227 | TRACE_FUN(ft_t_flow); | ||
228 | |||
229 | result = zft_skip_volumes(*arg, &zft_pos); | ||
230 | zft_just_before_eof = 0; | ||
231 | TRACE_EXIT result; | ||
232 | } | ||
233 | |||
234 | static int mt_bsf(int *arg) | ||
235 | { | ||
236 | int result = 0; | ||
237 | TRACE_FUN(ft_t_flow); | ||
238 | |||
239 | if (*arg != 0) { | ||
240 | result = zft_skip_volumes(-*arg + 1, &zft_pos); | ||
241 | } | ||
242 | TRACE_EXIT result; | ||
243 | } | ||
244 | |||
245 | static int seek_block(__s64 data_offset, | ||
246 | __s64 block_increment, | ||
247 | zft_position *pos) | ||
248 | { | ||
249 | int result = 0; | ||
250 | __s64 new_block_pos; | ||
251 | __s64 vol_block_count; | ||
252 | const zft_volinfo *volume; | ||
253 | int exceed; | ||
254 | TRACE_FUN(ft_t_flow); | ||
255 | |||
256 | volume = zft_find_volume(pos->seg_pos); | ||
257 | if (volume->start_seg == 0 || volume->end_seg == 0) { | ||
258 | TRACE_EXIT -EIO; | ||
259 | } | ||
260 | new_block_pos = (zft_div_blksz(data_offset, volume->blk_sz) | ||
261 | + block_increment); | ||
262 | vol_block_count = zft_div_blksz(volume->size, volume->blk_sz); | ||
263 | if (new_block_pos < 0) { | ||
264 | TRACE(ft_t_noise, | ||
265 | "new_block_pos " LL_X " < 0", LL(new_block_pos)); | ||
266 | zft_resid = (int)new_block_pos; | ||
267 | new_block_pos = 0; | ||
268 | exceed = 1; | ||
269 | } else if (new_block_pos > vol_block_count) { | ||
270 | TRACE(ft_t_noise, | ||
271 | "new_block_pos " LL_X " exceeds size of volume " LL_X, | ||
272 | LL(new_block_pos), LL(vol_block_count)); | ||
273 | zft_resid = (int)(vol_block_count - new_block_pos); | ||
274 | new_block_pos = vol_block_count; | ||
275 | exceed = 1; | ||
276 | } else { | ||
277 | exceed = 0; | ||
278 | } | ||
279 | if (zft_use_compression && volume->use_compression) { | ||
280 | TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); | ||
281 | result = (*zft_cmpr_ops->seek)(new_block_pos, pos, volume, | ||
282 | zft_deblock_buf); | ||
283 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
284 | pos->tape_pos += pos->seg_byte_pos; | ||
285 | } else { | ||
286 | pos->volume_pos = zft_mul_blksz(new_block_pos, volume->blk_sz); | ||
287 | pos->tape_pos = zft_calc_tape_pos(volume->start_seg); | ||
288 | pos->tape_pos += pos->volume_pos; | ||
289 | pos->seg_pos = zft_calc_seg_byte_coord(&pos->seg_byte_pos, | ||
290 | pos->tape_pos); | ||
291 | } | ||
292 | zft_just_before_eof = volume->size == pos->volume_pos; | ||
293 | if (zft_just_before_eof) { | ||
294 | /* why this? because zft_file_no checks agains start | ||
295 | * and end segment of a volume. We do not want to | ||
296 | * advance to the next volume with this function. | ||
297 | */ | ||
298 | TRACE(ft_t_noise, "set zft_just_before_eof"); | ||
299 | zft_position_before_eof(pos, volume); | ||
300 | } | ||
301 | TRACE(ft_t_noise, "\n" | ||
302 | KERN_INFO "new_seg_pos : %d\n" | ||
303 | KERN_INFO "new_tape_pos: " LL_X "\n" | ||
304 | KERN_INFO "vol_size : " LL_X "\n" | ||
305 | KERN_INFO "seg_byte_pos: %d\n" | ||
306 | KERN_INFO "blk_sz : %d", | ||
307 | pos->seg_pos, LL(pos->tape_pos), | ||
308 | LL(volume->size), pos->seg_byte_pos, | ||
309 | volume->blk_sz); | ||
310 | if (!exceed) { | ||
311 | zft_resid = new_block_pos - zft_div_blksz(pos->volume_pos, | ||
312 | volume->blk_sz); | ||
313 | } | ||
314 | if (zft_resid < 0) { | ||
315 | zft_resid = -zft_resid; | ||
316 | } | ||
317 | TRACE_EXIT ((exceed || zft_resid != 0) && result >= 0) ? -EINVAL : result; | ||
318 | } | ||
319 | |||
320 | static int mt_fsr(int *arg) | ||
321 | { | ||
322 | int result; | ||
323 | TRACE_FUN(ft_t_flow); | ||
324 | |||
325 | result = seek_block(zft_pos.volume_pos, *arg, &zft_pos); | ||
326 | TRACE_EXIT result; | ||
327 | } | ||
328 | |||
329 | static int mt_bsr(int *arg) | ||
330 | { | ||
331 | int result; | ||
332 | TRACE_FUN(ft_t_flow); | ||
333 | |||
334 | result = seek_block(zft_pos.volume_pos, -*arg, &zft_pos); | ||
335 | TRACE_EXIT result; | ||
336 | } | ||
337 | |||
338 | static int mt_weof(int *arg) | ||
339 | { | ||
340 | int result; | ||
341 | TRACE_FUN(ft_t_flow); | ||
342 | |||
343 | TRACE_CATCH(zft_flush_buffers(),); | ||
344 | result = zft_weof(*arg, &zft_pos); | ||
345 | TRACE_EXIT result; | ||
346 | } | ||
347 | |||
348 | static int mt_rew(int *dummy) | ||
349 | { | ||
350 | int result; | ||
351 | TRACE_FUN(ft_t_flow); | ||
352 | |||
353 | if(zft_header_read) { | ||
354 | (void)zft_def_idle_state(); | ||
355 | } | ||
356 | result = ftape_seek_to_bot(); | ||
357 | zft_reset_position(&zft_pos); | ||
358 | TRACE_EXIT result; | ||
359 | } | ||
360 | |||
361 | static int mt_offl(int *dummy) | ||
362 | { | ||
363 | int result; | ||
364 | TRACE_FUN(ft_t_flow); | ||
365 | |||
366 | going_offline= 1; | ||
367 | result = mt_rew(NULL); | ||
368 | TRACE_EXIT result; | ||
369 | } | ||
370 | |||
371 | static int mt_nop(int *dummy) | ||
372 | { | ||
373 | TRACE_FUN(ft_t_flow); | ||
374 | /* should we set tape status? | ||
375 | */ | ||
376 | if (!zft_offline) { /* offline includes no_tape */ | ||
377 | (void)zft_def_idle_state(); | ||
378 | } | ||
379 | TRACE_EXIT 0; | ||
380 | } | ||
381 | |||
382 | static int mt_reten(int *dummy) | ||
383 | { | ||
384 | int result; | ||
385 | TRACE_FUN(ft_t_flow); | ||
386 | |||
387 | if(zft_header_read) { | ||
388 | (void)zft_def_idle_state(); | ||
389 | } | ||
390 | result = ftape_seek_to_eot(); | ||
391 | if (result >= 0) { | ||
392 | result = ftape_seek_to_bot(); | ||
393 | } | ||
394 | TRACE_EXIT(result); | ||
395 | } | ||
396 | |||
397 | static int fsfbsfm(int arg, zft_position *pos) | ||
398 | { | ||
399 | const zft_volinfo *vtbl; | ||
400 | __s64 block_pos; | ||
401 | TRACE_FUN(ft_t_flow); | ||
402 | |||
403 | /* What to do? This should seek to the next file-mark and | ||
404 | * position BEFORE. That is, a next write would just extend | ||
405 | * the current file. Well. Let's just seek to the end of the | ||
406 | * current file, if count == 1. If count > 1, then do a | ||
407 | * "mt_fsf(count - 1)", and then seek to the end of that file. | ||
408 | * If count == 0, do nothing | ||
409 | */ | ||
410 | if (arg == 0) { | ||
411 | TRACE_EXIT 0; | ||
412 | } | ||
413 | zft_just_before_eof = 0; | ||
414 | TRACE_CATCH(zft_skip_volumes(arg < 0 ? arg : arg-1, pos), | ||
415 | if (arg > 0) { | ||
416 | zft_resid ++; | ||
417 | }); | ||
418 | vtbl = zft_find_volume(pos->seg_pos); | ||
419 | block_pos = zft_div_blksz(vtbl->size, vtbl->blk_sz); | ||
420 | (void)seek_block(0, block_pos, pos); | ||
421 | if (pos->volume_pos != vtbl->size) { | ||
422 | zft_just_before_eof = 0; | ||
423 | zft_resid = 1; | ||
424 | /* we didn't managed to go there */ | ||
425 | TRACE_ABORT(-EIO, ft_t_err, | ||
426 | "wanted file position " LL_X ", arrived at " LL_X, | ||
427 | LL(vtbl->size), LL(pos->volume_pos)); | ||
428 | } | ||
429 | zft_just_before_eof = 1; | ||
430 | TRACE_EXIT 0; | ||
431 | } | ||
432 | |||
433 | static int mt_bsfm(int *arg) | ||
434 | { | ||
435 | int result; | ||
436 | TRACE_FUN(ft_t_flow); | ||
437 | |||
438 | result = fsfbsfm(-*arg, &zft_pos); | ||
439 | TRACE_EXIT result; | ||
440 | } | ||
441 | |||
442 | static int mt_fsfm(int *arg) | ||
443 | { | ||
444 | int result; | ||
445 | TRACE_FUN(ft_t_flow); | ||
446 | |||
447 | result = fsfbsfm(*arg, &zft_pos); | ||
448 | TRACE_EXIT result; | ||
449 | } | ||
450 | |||
451 | static int mt_eom(int *dummy) | ||
452 | { | ||
453 | TRACE_FUN(ft_t_flow); | ||
454 | |||
455 | zft_skip_to_eom(&zft_pos); | ||
456 | TRACE_EXIT 0; | ||
457 | } | ||
458 | |||
459 | static int mt_erase(int *dummy) | ||
460 | { | ||
461 | int result; | ||
462 | TRACE_FUN(ft_t_flow); | ||
463 | |||
464 | result = zft_erase(); | ||
465 | TRACE_EXIT result; | ||
466 | } | ||
467 | |||
468 | static int mt_ras2(int *dummy) | ||
469 | { | ||
470 | int result; | ||
471 | TRACE_FUN(ft_t_flow); | ||
472 | |||
473 | result = -ENOSYS; | ||
474 | TRACE_EXIT result; | ||
475 | } | ||
476 | |||
477 | /* Sets the new blocksize in BYTES | ||
478 | * | ||
479 | */ | ||
480 | static int mt_setblk(int *new_size) | ||
481 | { | ||
482 | TRACE_FUN(ft_t_flow); | ||
483 | |||
484 | if((unsigned int)(*new_size) > ZFT_MAX_BLK_SZ) { | ||
485 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
486 | "desired blk_sz (%d) should be <= %d bytes", | ||
487 | *new_size, ZFT_MAX_BLK_SZ); | ||
488 | } | ||
489 | if ((*new_size & (FT_SECTOR_SIZE-1)) != 0) { | ||
490 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
491 | "desired blk_sz (%d) must be a multiple of %d bytes", | ||
492 | *new_size, FT_SECTOR_SIZE); | ||
493 | } | ||
494 | if (*new_size == 0) { | ||
495 | if (zft_use_compression) { | ||
496 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
497 | "Variable block size not yet " | ||
498 | "supported with compression"); | ||
499 | } | ||
500 | *new_size = 1; | ||
501 | } | ||
502 | zft_blk_sz = *new_size; | ||
503 | TRACE_EXIT 0; | ||
504 | } | ||
505 | |||
506 | static int mt_setdensity(int *arg) | ||
507 | { | ||
508 | TRACE_FUN(ft_t_flow); | ||
509 | |||
510 | SET_TRACE_LEVEL(*arg); | ||
511 | TRACE(TRACE_LEVEL, "tracing set to %d", TRACE_LEVEL); | ||
512 | if ((int)TRACE_LEVEL != *arg) { | ||
513 | TRACE_EXIT -EINVAL; | ||
514 | } | ||
515 | TRACE_EXIT 0; | ||
516 | } | ||
517 | |||
518 | static int mt_seek(int *new_block_pos) | ||
519 | { | ||
520 | int result= 0; | ||
521 | TRACE_FUN(ft_t_any); | ||
522 | |||
523 | result = seek_block(0, (__s64)*new_block_pos, &zft_pos); | ||
524 | TRACE_EXIT result; | ||
525 | } | ||
526 | |||
527 | /* OK, this is totally different from SCSI, but the worst thing that can | ||
528 | * happen is that there is not enough defragmentated memory that can be | ||
529 | * allocated. Also, there is a hardwired limit of 16 dma buffers in the | ||
530 | * stock ftape module. This shouldn't bring the system down. | ||
531 | * | ||
532 | * NOTE: the argument specifies the total number of dma buffers to use. | ||
533 | * The driver needs at least 3 buffers to function at all. | ||
534 | * | ||
535 | */ | ||
536 | static int mt_setdrvbuffer(int *cnt) | ||
537 | { | ||
538 | TRACE_FUN(ft_t_flow); | ||
539 | |||
540 | if (*cnt < 3) { | ||
541 | TRACE_EXIT -EINVAL; | ||
542 | } | ||
543 | TRACE_CATCH(ftape_set_nr_buffers(*cnt),); | ||
544 | TRACE_EXIT 0; | ||
545 | } | ||
546 | /* return the block position from start of volume | ||
547 | */ | ||
548 | static int mt_tell(int *arg) | ||
549 | { | ||
550 | TRACE_FUN(ft_t_flow); | ||
551 | |||
552 | *arg = zft_div_blksz(zft_pos.volume_pos, | ||
553 | zft_find_volume(zft_pos.seg_pos)->blk_sz); | ||
554 | TRACE_EXIT 0; | ||
555 | } | ||
556 | |||
557 | static int mt_compression(int *arg) | ||
558 | { | ||
559 | TRACE_FUN(ft_t_flow); | ||
560 | |||
561 | /* Ok. We could also check whether compression is available at | ||
562 | * all by trying to load the compression module. We could | ||
563 | * also check for a block size of 1 byte which is illegal | ||
564 | * with compression. Instead of doing it here we rely on | ||
565 | * zftape_write() to do the proper checks. | ||
566 | */ | ||
567 | if ((unsigned int)*arg > 1) { | ||
568 | TRACE_EXIT -EINVAL; | ||
569 | } | ||
570 | if (*arg != 0 && zft_blk_sz == 1) { /* variable block size */ | ||
571 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
572 | "Compression not yet supported " | ||
573 | "with variable block size"); | ||
574 | } | ||
575 | zft_mt_compression = *arg; | ||
576 | if ((zft_unit & ZFT_ZIP_MODE) == 0) { | ||
577 | zft_use_compression = zft_mt_compression; | ||
578 | } | ||
579 | TRACE_EXIT 0; | ||
580 | } | ||
581 | |||
582 | /* check whether write access is allowed. Write access is denied when | ||
583 | * + zft_write_protected == 1 -- this accounts for either hard write | ||
584 | * protection of the cartridge or for | ||
585 | * O_RDONLY access mode of the tape device | ||
586 | * + zft_offline == 1 -- this meany that there is either no tape | ||
587 | * or that the MTOFFLINE ioctl has been | ||
588 | * previously issued (`soft eject') | ||
589 | * + ft_formatted == 0 -- this means that the cartridge is not | ||
590 | * formatted | ||
591 | * Then we distinuguish two cases. When zft_qic_mode is TRUE, then we try | ||
592 | * to emulate a `traditional' (aka SCSI like) UN*X tape device. Therefore we | ||
593 | * deny writes when | ||
594 | * + zft_qic_mode ==1 && | ||
595 | * (!zft_tape_at_lbot() && -- tape no at logical BOT | ||
596 | * !(zft_tape_at_eom() || -- tape not at logical EOM (or EOD) | ||
597 | * (zft_tape_at_eom() && | ||
598 | * zft_old_ftape()))) -- we can't add new volume to tapes | ||
599 | * written by old ftape because ftape | ||
600 | * don't use the volume table | ||
601 | * | ||
602 | * when the drive is in true raw mode (aka /dev/rawft0) then we don't | ||
603 | * care about LBOT and EOM conditions. This device is intended for a | ||
604 | * user level program that wants to truly implement the QIC-80 compliance | ||
605 | * at the logical data layout level of the cartridge, i.e. implement all | ||
606 | * that volume table and volume directory stuff etc.< | ||
607 | */ | ||
608 | int zft_check_write_access(zft_position *pos) | ||
609 | { | ||
610 | TRACE_FUN(ft_t_flow); | ||
611 | |||
612 | if (zft_offline) { /* offline includes no_tape */ | ||
613 | TRACE_ABORT(-ENXIO, | ||
614 | ft_t_info, "tape is offline or no cartridge"); | ||
615 | } | ||
616 | if (!ft_formatted) { | ||
617 | TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); | ||
618 | } | ||
619 | if (zft_write_protected) { | ||
620 | TRACE_ABORT(-EACCES, ft_t_info, "cartridge write protected"); | ||
621 | } | ||
622 | if (zft_qic_mode) { | ||
623 | /* check BOT condition */ | ||
624 | if (!zft_tape_at_lbot(pos)) { | ||
625 | /* protect cartridges written by old ftape if | ||
626 | * not at BOT because they use the vtbl | ||
627 | * segment for storing data | ||
628 | */ | ||
629 | if (zft_old_ftape) { | ||
630 | TRACE_ABORT(-EACCES, ft_t_warn, | ||
631 | "Cannot write to cartridges written by old ftape when not at BOT"); | ||
632 | } | ||
633 | /* not at BOT, but allow writes at EOD, of course | ||
634 | */ | ||
635 | if (!zft_tape_at_eod(pos)) { | ||
636 | TRACE_ABORT(-EACCES, ft_t_info, | ||
637 | "tape not at BOT and not at EOD"); | ||
638 | } | ||
639 | } | ||
640 | /* fine. Now the tape is either at BOT or at EOD. */ | ||
641 | } | ||
642 | /* or in raw mode in which case we don't care about BOT and EOD */ | ||
643 | TRACE_EXIT 0; | ||
644 | } | ||
645 | |||
646 | /* OPEN routine called by kernel-interface code | ||
647 | * | ||
648 | * NOTE: this is also called by mt_reset() with dev_minor == -1 | ||
649 | * to fake a reopen after a reset. | ||
650 | */ | ||
651 | int _zft_open(unsigned int dev_minor, unsigned int access_mode) | ||
652 | { | ||
653 | static unsigned int tape_unit; | ||
654 | static unsigned int file_access_mode; | ||
655 | int result; | ||
656 | TRACE_FUN(ft_t_flow); | ||
657 | |||
658 | if ((int)dev_minor == -1) { | ||
659 | /* fake reopen */ | ||
660 | zft_unit = tape_unit; | ||
661 | access_mode = file_access_mode; | ||
662 | zft_init_driver(); /* reset all static data to defaults */ | ||
663 | } else { | ||
664 | tape_unit = dev_minor; | ||
665 | file_access_mode = access_mode; | ||
666 | if ((result = ftape_enable(FTAPE_SEL(dev_minor))) < 0) { | ||
667 | TRACE_ABORT(-ENXIO, ft_t_err, | ||
668 | "ftape_enable failed: %d", result); | ||
669 | } | ||
670 | if (ft_new_tape || ft_no_tape || !ft_formatted || | ||
671 | (FTAPE_SEL(zft_unit) != FTAPE_SEL(dev_minor)) || | ||
672 | (zft_unit & ZFT_RAW_MODE) != (dev_minor & ZFT_RAW_MODE)) { | ||
673 | /* reset all static data to defaults, | ||
674 | */ | ||
675 | zft_init_driver(); | ||
676 | } | ||
677 | zft_unit = dev_minor; | ||
678 | } | ||
679 | zft_set_flags(zft_unit); /* decode the minor bits */ | ||
680 | if (zft_blk_sz == 1 && zft_use_compression) { | ||
681 | ftape_disable(); /* resets ft_no_tape */ | ||
682 | TRACE_ABORT(-ENODEV, ft_t_warn, "Variable block size not yet " | ||
683 | "supported with compression"); | ||
684 | } | ||
685 | /* no need for most of the buffers when no tape or not | ||
686 | * formatted. for the read/write operations, it is the | ||
687 | * regardless whether there is no tape, a not-formatted tape | ||
688 | * or the whether the driver is soft offline. | ||
689 | * Nevertheless we allow some ioctls with non-formatted tapes, | ||
690 | * like rewind and reset. | ||
691 | */ | ||
692 | if (ft_no_tape || !ft_formatted) { | ||
693 | zft_uninit_mem(); | ||
694 | } | ||
695 | if (ft_no_tape) { | ||
696 | zft_offline = 1; /* so we need not test two variables */ | ||
697 | } | ||
698 | if ((access_mode == O_WRONLY || access_mode == O_RDWR) && | ||
699 | (ft_write_protected || ft_no_tape)) { | ||
700 | ftape_disable(); /* resets ft_no_tape */ | ||
701 | TRACE_ABORT(ft_no_tape ? -ENXIO : -EROFS, | ||
702 | ft_t_warn, "wrong access mode %s cartridge", | ||
703 | ft_no_tape ? "without a" : "with write protected"); | ||
704 | } | ||
705 | zft_write_protected = (access_mode == O_RDONLY || | ||
706 | ft_write_protected != 0); | ||
707 | if (zft_write_protected) { | ||
708 | TRACE(ft_t_noise, | ||
709 | "read only access mode: %d, " | ||
710 | "drive write protected: %d", | ||
711 | access_mode == O_RDONLY, | ||
712 | ft_write_protected != 0); | ||
713 | } | ||
714 | if (!zft_offline) { | ||
715 | TRACE_CATCH(zft_vmalloc_once(&zft_deblock_buf,FT_SEGMENT_SIZE), | ||
716 | ftape_disable()); | ||
717 | } | ||
718 | /* zft_seg_pos should be greater than the vtbl segpos but not | ||
719 | * if in compatibility mode and only after we read in the | ||
720 | * header segments | ||
721 | * | ||
722 | * might also be a problem if the user makes a backup with a | ||
723 | * *qft* device and rewinds it with a raw device. | ||
724 | */ | ||
725 | if (zft_qic_mode && | ||
726 | !zft_old_ftape && | ||
727 | zft_pos.seg_pos >= 0 && | ||
728 | zft_header_read && | ||
729 | zft_pos.seg_pos <= ft_first_data_segment) { | ||
730 | TRACE(ft_t_noise, "you probably mixed up the zftape devices!"); | ||
731 | zft_reset_position(&zft_pos); | ||
732 | } | ||
733 | TRACE_EXIT 0; | ||
734 | } | ||
735 | |||
736 | /* RELEASE routine called by kernel-interface code | ||
737 | */ | ||
738 | int _zft_close(void) | ||
739 | { | ||
740 | int result = 0; | ||
741 | TRACE_FUN(ft_t_flow); | ||
742 | |||
743 | if (zft_offline) { | ||
744 | /* call the hardware release routine. Puts the drive offline */ | ||
745 | ftape_disable(); | ||
746 | TRACE_EXIT 0; | ||
747 | } | ||
748 | if (!(ft_write_protected || zft_old_ftape)) { | ||
749 | result = zft_flush_buffers(); | ||
750 | TRACE(ft_t_noise, "writing file mark at current position"); | ||
751 | if (zft_qic_mode && zft_close_volume(&zft_pos) == 0) { | ||
752 | zft_move_past_eof(&zft_pos); | ||
753 | } | ||
754 | if ((zft_tape_at_lbot(&zft_pos) || | ||
755 | !(zft_unit & FTAPE_NO_REWIND))) { | ||
756 | if (result >= 0) { | ||
757 | result = zft_update_header_segments(); | ||
758 | } else { | ||
759 | TRACE(ft_t_err, | ||
760 | "Error: unable to update header segments"); | ||
761 | } | ||
762 | } | ||
763 | } | ||
764 | ftape_abort_operation(); | ||
765 | if (!(zft_unit & FTAPE_NO_REWIND)) { | ||
766 | TRACE(ft_t_noise, "rewinding tape"); | ||
767 | if (ftape_seek_to_bot() < 0 && result >= 0) { | ||
768 | result = -EIO; /* keep old value */ | ||
769 | } | ||
770 | zft_reset_position(&zft_pos); | ||
771 | } | ||
772 | zft_zap_read_buffers(); | ||
773 | /* now free up memory as much as possible. We don't destroy | ||
774 | * the deblock buffer if it containes a valid segment. | ||
775 | */ | ||
776 | if (zft_deblock_segment == -1) { | ||
777 | zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); | ||
778 | } | ||
779 | /* high level driver status, forces creation of a new volume | ||
780 | * when calling ftape_write again and not zft_just_before_eof | ||
781 | */ | ||
782 | zft_io_state = zft_idle; | ||
783 | if (going_offline) { | ||
784 | zft_init_driver(); | ||
785 | zft_uninit_mem(); | ||
786 | going_offline = 0; | ||
787 | zft_offline = 1; | ||
788 | } else if (zft_cmpr_lock(0 /* don't load */) == 0) { | ||
789 | (*zft_cmpr_ops->reset)(); /* unlock it again */ | ||
790 | } | ||
791 | zft_memory_stats(); | ||
792 | /* call the hardware release routine. Puts the drive offline */ | ||
793 | ftape_disable(); | ||
794 | TRACE_EXIT result; | ||
795 | } | ||
796 | |||
797 | /* | ||
798 | * the wrapper function around the wrapper MTIOCTOP ioctl | ||
799 | */ | ||
800 | static int mtioctop(struct mtop *mtop, int arg_size) | ||
801 | { | ||
802 | int result = 0; | ||
803 | fun_entry *mt_fun_entry; | ||
804 | TRACE_FUN(ft_t_flow); | ||
805 | |||
806 | if (arg_size != sizeof(struct mtop) || mtop->mt_op >= NR_MT_CMDS) { | ||
807 | TRACE_EXIT -EINVAL; | ||
808 | } | ||
809 | TRACE(ft_t_noise, "calling MTIOCTOP command: %s", | ||
810 | mt_funs[mtop->mt_op].name); | ||
811 | mt_fun_entry= &mt_funs[mtop->mt_op]; | ||
812 | zft_resid = mtop->mt_count; | ||
813 | if (!mt_fun_entry->offline && zft_offline) { | ||
814 | if (ft_no_tape) { | ||
815 | TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); | ||
816 | } else { | ||
817 | TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); | ||
818 | } | ||
819 | } | ||
820 | if (!mt_fun_entry->not_formatted && !ft_formatted) { | ||
821 | TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); | ||
822 | } | ||
823 | if (!mt_fun_entry->write_protected) { | ||
824 | TRACE_CATCH(zft_check_write_access(&zft_pos),); | ||
825 | } | ||
826 | if (mt_fun_entry->need_idle_state && !(zft_offline || !ft_formatted)) { | ||
827 | TRACE_CATCH(zft_def_idle_state(),); | ||
828 | } | ||
829 | if (!zft_qic_mode && !mt_fun_entry->raw_mode) { | ||
830 | TRACE_ABORT(-EACCES, ft_t_info, | ||
831 | "Drive needs to be in QIC-80 compatibility mode for this command"); | ||
832 | } | ||
833 | result = (mt_fun_entry->function)(&mtop->mt_count); | ||
834 | if (zft_tape_at_lbot(&zft_pos)) { | ||
835 | TRACE_CATCH(zft_update_header_segments(),); | ||
836 | } | ||
837 | if (result >= 0) { | ||
838 | zft_resid = 0; | ||
839 | } | ||
840 | TRACE_EXIT result; | ||
841 | } | ||
842 | |||
843 | /* | ||
844 | * standard MTIOCGET ioctl | ||
845 | */ | ||
846 | static int mtiocget(struct mtget *mtget, int arg_size) | ||
847 | { | ||
848 | const zft_volinfo *volume; | ||
849 | __s64 max_tape_pos; | ||
850 | TRACE_FUN(ft_t_flow); | ||
851 | |||
852 | if (arg_size != sizeof(struct mtget)) { | ||
853 | TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", | ||
854 | arg_size); | ||
855 | } | ||
856 | mtget->mt_type = ft_drive_type.vendor_id + 0x800000; | ||
857 | mtget->mt_dsreg = ft_last_status.space; | ||
858 | mtget->mt_erreg = ft_last_error.space; /* error register */ | ||
859 | mtget->mt_resid = zft_resid; /* residuum of writes, reads and | ||
860 | * MTIOCTOP commands | ||
861 | */ | ||
862 | if (!zft_offline) { /* neither no_tape nor soft offline */ | ||
863 | mtget->mt_gstat = GMT_ONLINE(~0UL); | ||
864 | /* should rather return the status of the cartridge | ||
865 | * than the access mode of the file, therefor use | ||
866 | * ft_write_protected, not zft_write_protected | ||
867 | */ | ||
868 | if (ft_write_protected) { | ||
869 | mtget->mt_gstat |= GMT_WR_PROT(~0UL); | ||
870 | } | ||
871 | if(zft_header_read) { /* this catches non-formatted */ | ||
872 | volume = zft_find_volume(zft_pos.seg_pos); | ||
873 | mtget->mt_fileno = volume->count; | ||
874 | max_tape_pos = zft_capacity - zft_blk_sz; | ||
875 | if (zft_use_compression) { | ||
876 | max_tape_pos -= ZFT_CMPR_OVERHEAD; | ||
877 | } | ||
878 | if (zft_tape_at_eod(&zft_pos)) { | ||
879 | mtget->mt_gstat |= GMT_EOD(~0UL); | ||
880 | } | ||
881 | if (zft_pos.tape_pos > max_tape_pos) { | ||
882 | mtget->mt_gstat |= GMT_EOT(~0UL); | ||
883 | } | ||
884 | mtget->mt_blkno = zft_div_blksz(zft_pos.volume_pos, | ||
885 | volume->blk_sz); | ||
886 | if (zft_just_before_eof) { | ||
887 | mtget->mt_gstat |= GMT_EOF(~0UL); | ||
888 | } | ||
889 | if (zft_tape_at_lbot(&zft_pos)) { | ||
890 | mtget->mt_gstat |= GMT_BOT(~0UL); | ||
891 | } | ||
892 | } else { | ||
893 | mtget->mt_fileno = mtget->mt_blkno = -1; | ||
894 | if (mtget->mt_dsreg & QIC_STATUS_AT_BOT) { | ||
895 | mtget->mt_gstat |= GMT_BOT(~0UL); | ||
896 | } | ||
897 | } | ||
898 | } else { | ||
899 | if (ft_no_tape) { | ||
900 | mtget->mt_gstat = GMT_DR_OPEN(~0UL); | ||
901 | } else { | ||
902 | mtget->mt_gstat = 0UL; | ||
903 | } | ||
904 | mtget->mt_fileno = mtget->mt_blkno = -1; | ||
905 | } | ||
906 | TRACE_EXIT 0; | ||
907 | } | ||
908 | |||
909 | #ifdef MTIOCRDFTSEG | ||
910 | /* | ||
911 | * Read a floppy tape segment. This is useful for manipulating the | ||
912 | * volume table, and read the old header segment before re-formatting | ||
913 | * the cartridge. | ||
914 | */ | ||
915 | static int mtiocrdftseg(struct mtftseg * mtftseg, int arg_size) | ||
916 | { | ||
917 | TRACE_FUN(ft_t_flow); | ||
918 | |||
919 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCRDFTSEG"); | ||
920 | if (zft_qic_mode) { | ||
921 | TRACE_ABORT(-EACCES, ft_t_info, | ||
922 | "driver needs to be in raw mode for this ioctl"); | ||
923 | } | ||
924 | if (arg_size != sizeof(struct mtftseg)) { | ||
925 | TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", | ||
926 | arg_size); | ||
927 | } | ||
928 | if (zft_offline) { | ||
929 | TRACE_EXIT -ENXIO; | ||
930 | } | ||
931 | if (mtftseg->mt_mode != FT_RD_SINGLE && | ||
932 | mtftseg->mt_mode != FT_RD_AHEAD) { | ||
933 | TRACE_ABORT(-EINVAL, ft_t_info, "invalid read mode"); | ||
934 | } | ||
935 | if (!ft_formatted) { | ||
936 | TRACE_EXIT -EACCES; /* -ENXIO ? */ | ||
937 | |||
938 | } | ||
939 | if (!zft_header_read) { | ||
940 | TRACE_CATCH(zft_def_idle_state(),); | ||
941 | } | ||
942 | if (mtftseg->mt_segno > ft_last_data_segment) { | ||
943 | TRACE_ABORT(-EINVAL, ft_t_info, "segment number is too large"); | ||
944 | } | ||
945 | mtftseg->mt_result = ftape_read_segment(mtftseg->mt_segno, | ||
946 | zft_deblock_buf, | ||
947 | mtftseg->mt_mode); | ||
948 | if (mtftseg->mt_result < 0) { | ||
949 | /* a negativ result is not an ioctl error. if | ||
950 | * the user wants to read damaged tapes, | ||
951 | * it's up to her/him | ||
952 | */ | ||
953 | TRACE_EXIT 0; | ||
954 | } | ||
955 | if (copy_to_user(mtftseg->mt_data, | ||
956 | zft_deblock_buf, | ||
957 | mtftseg->mt_result) != 0) { | ||
958 | TRACE_EXIT -EFAULT; | ||
959 | } | ||
960 | TRACE_EXIT 0; | ||
961 | } | ||
962 | #endif | ||
963 | |||
964 | #ifdef MTIOCWRFTSEG | ||
965 | /* | ||
966 | * write a floppy tape segment. This version features writing of | ||
967 | * deleted address marks, and gracefully ignores the (software) | ||
968 | * ft_formatted flag to support writing of header segments after | ||
969 | * formatting. | ||
970 | */ | ||
971 | static int mtiocwrftseg(struct mtftseg * mtftseg, int arg_size) | ||
972 | { | ||
973 | int result; | ||
974 | TRACE_FUN(ft_t_flow); | ||
975 | |||
976 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCWRFTSEG"); | ||
977 | if (zft_write_protected || zft_qic_mode) { | ||
978 | TRACE_EXIT -EACCES; | ||
979 | } | ||
980 | if (arg_size != sizeof(struct mtftseg)) { | ||
981 | TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", | ||
982 | arg_size); | ||
983 | } | ||
984 | if (zft_offline) { | ||
985 | TRACE_EXIT -ENXIO; | ||
986 | } | ||
987 | if (mtftseg->mt_mode != FT_WR_ASYNC && | ||
988 | mtftseg->mt_mode != FT_WR_MULTI && | ||
989 | mtftseg->mt_mode != FT_WR_SINGLE && | ||
990 | mtftseg->mt_mode != FT_WR_DELETE) { | ||
991 | TRACE_ABORT(-EINVAL, ft_t_info, "invalid write mode"); | ||
992 | } | ||
993 | /* | ||
994 | * We don't check for ft_formatted, because this gives | ||
995 | * only the software status of the driver. | ||
996 | * | ||
997 | * We assume that the user knows what it is | ||
998 | * doing. And rely on the low level stuff to fail | ||
999 | * when the tape isn't formatted. We only make sure | ||
1000 | * that The header segment buffer is allocated, | ||
1001 | * because it holds the bad sector map. | ||
1002 | */ | ||
1003 | if (zft_hseg_buf == NULL) { | ||
1004 | TRACE_EXIT -ENXIO; | ||
1005 | } | ||
1006 | if (mtftseg->mt_mode != FT_WR_DELETE) { | ||
1007 | if (copy_from_user(zft_deblock_buf, | ||
1008 | mtftseg->mt_data, | ||
1009 | FT_SEGMENT_SIZE) != 0) { | ||
1010 | TRACE_EXIT -EFAULT; | ||
1011 | } | ||
1012 | } | ||
1013 | mtftseg->mt_result = ftape_write_segment(mtftseg->mt_segno, | ||
1014 | zft_deblock_buf, | ||
1015 | mtftseg->mt_mode); | ||
1016 | if (mtftseg->mt_result >= 0 && mtftseg->mt_mode == FT_WR_SINGLE) { | ||
1017 | /* | ||
1018 | * a negativ result is not an ioctl error. if | ||
1019 | * the user wants to write damaged tapes, | ||
1020 | * it's up to her/him | ||
1021 | */ | ||
1022 | if ((result = ftape_loop_until_writes_done()) < 0) { | ||
1023 | mtftseg->mt_result = result; | ||
1024 | } | ||
1025 | } | ||
1026 | TRACE_EXIT 0; | ||
1027 | } | ||
1028 | #endif | ||
1029 | |||
1030 | #ifdef MTIOCVOLINFO | ||
1031 | /* | ||
1032 | * get information about volume positioned at. | ||
1033 | */ | ||
1034 | static int mtiocvolinfo(struct mtvolinfo *volinfo, int arg_size) | ||
1035 | { | ||
1036 | const zft_volinfo *volume; | ||
1037 | TRACE_FUN(ft_t_flow); | ||
1038 | |||
1039 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCVOLINFO"); | ||
1040 | if (arg_size != sizeof(struct mtvolinfo)) { | ||
1041 | TRACE_ABORT(-EINVAL, | ||
1042 | ft_t_info, "bad argument size: %d", arg_size); | ||
1043 | } | ||
1044 | if (zft_offline) { | ||
1045 | TRACE_EXIT -ENXIO; | ||
1046 | } | ||
1047 | if (!ft_formatted) { | ||
1048 | TRACE_EXIT -EACCES; | ||
1049 | } | ||
1050 | TRACE_CATCH(zft_def_idle_state(),); | ||
1051 | volume = zft_find_volume(zft_pos.seg_pos); | ||
1052 | volinfo->mt_volno = volume->count; | ||
1053 | volinfo->mt_blksz = volume->blk_sz == 1 ? 0 : volume->blk_sz; | ||
1054 | volinfo->mt_size = volume->size >> 10; | ||
1055 | volinfo->mt_rawsize = ((zft_calc_tape_pos(volume->end_seg + 1) >> 10) - | ||
1056 | (zft_calc_tape_pos(volume->start_seg) >> 10)); | ||
1057 | volinfo->mt_cmpr = volume->use_compression; | ||
1058 | TRACE_EXIT 0; | ||
1059 | } | ||
1060 | #endif | ||
1061 | |||
1062 | #ifdef ZFT_OBSOLETE | ||
1063 | static int mtioc_zftape_getblksz(struct mtblksz *blksz, int arg_size) | ||
1064 | { | ||
1065 | TRACE_FUN(ft_t_flow); | ||
1066 | |||
1067 | TRACE(ft_t_noise, "\n" | ||
1068 | KERN_INFO "Mag tape ioctl command: MTIOC_ZTAPE_GETBLKSZ\n" | ||
1069 | KERN_INFO "This ioctl is here merely for compatibility.\n" | ||
1070 | KERN_INFO "Please use MTIOCVOLINFO instead"); | ||
1071 | if (arg_size != sizeof(struct mtblksz)) { | ||
1072 | TRACE_ABORT(-EINVAL, | ||
1073 | ft_t_info, "bad argument size: %d", arg_size); | ||
1074 | } | ||
1075 | if (zft_offline) { | ||
1076 | TRACE_EXIT -ENXIO; | ||
1077 | } | ||
1078 | if (!ft_formatted) { | ||
1079 | TRACE_EXIT -EACCES; | ||
1080 | } | ||
1081 | TRACE_CATCH(zft_def_idle_state(),); | ||
1082 | blksz->mt_blksz = zft_find_volume(zft_pos.seg_pos)->blk_sz; | ||
1083 | TRACE_EXIT 0; | ||
1084 | } | ||
1085 | #endif | ||
1086 | |||
1087 | #ifdef MTIOCGETSIZE | ||
1088 | /* | ||
1089 | * get the capacity of the tape cartridge. | ||
1090 | */ | ||
1091 | static int mtiocgetsize(struct mttapesize *size, int arg_size) | ||
1092 | { | ||
1093 | TRACE_FUN(ft_t_flow); | ||
1094 | |||
1095 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOC_ZFTAPE_GETSIZE"); | ||
1096 | if (arg_size != sizeof(struct mttapesize)) { | ||
1097 | TRACE_ABORT(-EINVAL, | ||
1098 | ft_t_info, "bad argument size: %d", arg_size); | ||
1099 | } | ||
1100 | if (zft_offline) { | ||
1101 | TRACE_EXIT -ENXIO; | ||
1102 | } | ||
1103 | if (!ft_formatted) { | ||
1104 | TRACE_EXIT -EACCES; | ||
1105 | } | ||
1106 | TRACE_CATCH(zft_def_idle_state(),); | ||
1107 | size->mt_capacity = (unsigned int)(zft_capacity>>10); | ||
1108 | size->mt_used = (unsigned int)(zft_get_eom_pos()>>10); | ||
1109 | TRACE_EXIT 0; | ||
1110 | } | ||
1111 | #endif | ||
1112 | |||
1113 | static int mtiocpos(struct mtpos *mtpos, int arg_size) | ||
1114 | { | ||
1115 | int result; | ||
1116 | TRACE_FUN(ft_t_flow); | ||
1117 | |||
1118 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCPOS"); | ||
1119 | if (arg_size != sizeof(struct mtpos)) { | ||
1120 | TRACE_ABORT(-EINVAL, | ||
1121 | ft_t_info, "bad argument size: %d", arg_size); | ||
1122 | } | ||
1123 | result = mt_tell((int *)&mtpos->mt_blkno); | ||
1124 | TRACE_EXIT result; | ||
1125 | } | ||
1126 | |||
1127 | #ifdef MTIOCFTFORMAT | ||
1128 | /* | ||
1129 | * formatting of floppy tape cartridges. This is intended to be used | ||
1130 | * together with the MTIOCFTCMD ioctl and the new mmap feature | ||
1131 | */ | ||
1132 | |||
1133 | /* | ||
1134 | * This function uses ftape_decode_header_segment() to inform the low | ||
1135 | * level ftape module about the new parameters. | ||
1136 | * | ||
1137 | * It erases the hseg_buf. The calling process must specify all | ||
1138 | * parameters to assure proper operation. | ||
1139 | * | ||
1140 | * return values: -EINVAL - wrong argument size | ||
1141 | * -EINVAL - if ftape_decode_header_segment() failed. | ||
1142 | */ | ||
1143 | static int set_format_parms(struct ftfmtparms *p, __u8 *hseg_buf) | ||
1144 | { | ||
1145 | ft_trace_t old_level = TRACE_LEVEL; | ||
1146 | TRACE_FUN(ft_t_flow); | ||
1147 | |||
1148 | TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_SETPARMS"); | ||
1149 | memset(hseg_buf, 0, FT_SEGMENT_SIZE); | ||
1150 | PUT4(hseg_buf, FT_SIGNATURE, FT_HSEG_MAGIC); | ||
1151 | |||
1152 | /* fill in user specified parameters | ||
1153 | */ | ||
1154 | hseg_buf[FT_FMT_CODE] = (__u8)p->ft_fmtcode; | ||
1155 | PUT2(hseg_buf, FT_SPT, p->ft_spt); | ||
1156 | hseg_buf[FT_TPC] = (__u8)p->ft_tpc; | ||
1157 | hseg_buf[FT_FHM] = (__u8)p->ft_fhm; | ||
1158 | hseg_buf[FT_FTM] = (__u8)p->ft_ftm; | ||
1159 | |||
1160 | /* fill in sane defaults to make ftape happy. | ||
1161 | */ | ||
1162 | hseg_buf[FT_FSM] = (__u8)128; /* 128 is hard wired all over ftape */ | ||
1163 | if (p->ft_fmtcode == fmt_big) { | ||
1164 | PUT4(hseg_buf, FT_6_HSEG_1, 0); | ||
1165 | PUT4(hseg_buf, FT_6_HSEG_2, 1); | ||
1166 | PUT4(hseg_buf, FT_6_FRST_SEG, 2); | ||
1167 | PUT4(hseg_buf, FT_6_LAST_SEG, p->ft_spt * p->ft_tpc - 1); | ||
1168 | } else { | ||
1169 | PUT2(hseg_buf, FT_HSEG_1, 0); | ||
1170 | PUT2(hseg_buf, FT_HSEG_2, 1); | ||
1171 | PUT2(hseg_buf, FT_FRST_SEG, 2); | ||
1172 | PUT2(hseg_buf, FT_LAST_SEG, p->ft_spt * p->ft_tpc - 1); | ||
1173 | } | ||
1174 | |||
1175 | /* Synchronize with the low level module. This is particularly | ||
1176 | * needed for unformatted cartridges as the QIC std was previously | ||
1177 | * unknown BUT is needed to set data rate and to calculate timeouts. | ||
1178 | */ | ||
1179 | TRACE_CATCH(ftape_calibrate_data_rate(p->ft_qicstd&QIC_TAPE_STD_MASK), | ||
1180 | _res = -EINVAL); | ||
1181 | |||
1182 | /* The following will also recalcualte the timeouts for the tape | ||
1183 | * length and QIC std we want to format to. | ||
1184 | * abort with -EINVAL rather than -EIO | ||
1185 | */ | ||
1186 | SET_TRACE_LEVEL(ft_t_warn); | ||
1187 | TRACE_CATCH(ftape_decode_header_segment(hseg_buf), | ||
1188 | SET_TRACE_LEVEL(old_level); _res = -EINVAL); | ||
1189 | SET_TRACE_LEVEL(old_level); | ||
1190 | TRACE_EXIT 0; | ||
1191 | } | ||
1192 | |||
1193 | /* | ||
1194 | * Return the internal SOFTWARE status of the kernel driver. This does | ||
1195 | * NOT query the tape drive about its status. | ||
1196 | */ | ||
1197 | static int get_format_parms(struct ftfmtparms *p, __u8 *hseg_buffer) | ||
1198 | { | ||
1199 | TRACE_FUN(ft_t_flow); | ||
1200 | |||
1201 | TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_GETPARMS"); | ||
1202 | p->ft_qicstd = ft_qic_std; | ||
1203 | p->ft_fmtcode = ft_format_code; | ||
1204 | p->ft_fhm = hseg_buffer[FT_FHM]; | ||
1205 | p->ft_ftm = hseg_buffer[FT_FTM]; | ||
1206 | p->ft_spt = ft_segments_per_track; | ||
1207 | p->ft_tpc = ft_tracks_per_tape; | ||
1208 | TRACE_EXIT 0; | ||
1209 | } | ||
1210 | |||
1211 | static int mtiocftformat(struct mtftformat *mtftformat, int arg_size) | ||
1212 | { | ||
1213 | int result; | ||
1214 | union fmt_arg *arg = &mtftformat->fmt_arg; | ||
1215 | TRACE_FUN(ft_t_flow); | ||
1216 | |||
1217 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTFORMAT"); | ||
1218 | if (zft_offline) { | ||
1219 | if (ft_no_tape) { | ||
1220 | TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); | ||
1221 | } else { | ||
1222 | TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); | ||
1223 | } | ||
1224 | } | ||
1225 | if (zft_qic_mode) { | ||
1226 | TRACE_ABORT(-EACCES, ft_t_info, | ||
1227 | "driver needs to be in raw mode for this ioctl"); | ||
1228 | } | ||
1229 | if (zft_hseg_buf == NULL) { | ||
1230 | TRACE_CATCH(zft_vcalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); | ||
1231 | } | ||
1232 | zft_header_read = 0; | ||
1233 | switch(mtftformat->fmt_op) { | ||
1234 | case FTFMT_SET_PARMS: | ||
1235 | TRACE_CATCH(set_format_parms(&arg->fmt_parms, zft_hseg_buf),); | ||
1236 | TRACE_EXIT 0; | ||
1237 | case FTFMT_GET_PARMS: | ||
1238 | TRACE_CATCH(get_format_parms(&arg->fmt_parms, zft_hseg_buf),); | ||
1239 | TRACE_EXIT 0; | ||
1240 | case FTFMT_FORMAT_TRACK: | ||
1241 | if ((ft_formatted && zft_check_write_access(&zft_pos) < 0) || | ||
1242 | (!ft_formatted && zft_write_protected)) { | ||
1243 | TRACE_ABORT(-EACCES, ft_t_info, "Write access denied"); | ||
1244 | } | ||
1245 | TRACE_CATCH(ftape_format_track(arg->fmt_track.ft_track, | ||
1246 | arg->fmt_track.ft_gap3),); | ||
1247 | TRACE_EXIT 0; | ||
1248 | case FTFMT_STATUS: | ||
1249 | TRACE_CATCH(ftape_format_status(&arg->fmt_status.ft_segment),); | ||
1250 | TRACE_EXIT 0; | ||
1251 | case FTFMT_VERIFY: | ||
1252 | TRACE_CATCH(ftape_verify_segment(arg->fmt_verify.ft_segment, | ||
1253 | (SectorMap *)&arg->fmt_verify.ft_bsm),); | ||
1254 | TRACE_EXIT 0; | ||
1255 | default: | ||
1256 | TRACE_ABORT(-EINVAL, ft_t_err, "Invalid format operation"); | ||
1257 | } | ||
1258 | TRACE_EXIT result; | ||
1259 | } | ||
1260 | #endif | ||
1261 | |||
1262 | #ifdef MTIOCFTCMD | ||
1263 | /* | ||
1264 | * send a QIC-117 command to the drive, with optional timeouts, | ||
1265 | * parameter and result bits. This is intended to be used together | ||
1266 | * with the formatting ioctl. | ||
1267 | */ | ||
1268 | static int mtiocftcmd(struct mtftcmd *ftcmd, int arg_size) | ||
1269 | { | ||
1270 | int i; | ||
1271 | TRACE_FUN(ft_t_flow); | ||
1272 | |||
1273 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTCMD"); | ||
1274 | if (!capable(CAP_SYS_ADMIN)) { | ||
1275 | TRACE_ABORT(-EPERM, ft_t_info, | ||
1276 | "need CAP_SYS_ADMIN capability to send raw qic-117 commands"); | ||
1277 | } | ||
1278 | if (zft_qic_mode) { | ||
1279 | TRACE_ABORT(-EACCES, ft_t_info, | ||
1280 | "driver needs to be in raw mode for this ioctl"); | ||
1281 | } | ||
1282 | if (arg_size != sizeof(struct mtftcmd)) { | ||
1283 | TRACE_ABORT(-EINVAL, | ||
1284 | ft_t_info, "bad argument size: %d", arg_size); | ||
1285 | } | ||
1286 | if (ftcmd->ft_wait_before) { | ||
1287 | TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_before, | ||
1288 | &ftcmd->ft_status),); | ||
1289 | } | ||
1290 | if (ftcmd->ft_status & QIC_STATUS_ERROR) | ||
1291 | goto ftmtcmd_error; | ||
1292 | if (ftcmd->ft_result_bits != 0) { | ||
1293 | TRACE_CATCH(ftape_report_operation(&ftcmd->ft_result, | ||
1294 | ftcmd->ft_cmd, | ||
1295 | ftcmd->ft_result_bits),); | ||
1296 | } else { | ||
1297 | TRACE_CATCH(ftape_command(ftcmd->ft_cmd),); | ||
1298 | if (ftcmd->ft_status & QIC_STATUS_ERROR) | ||
1299 | goto ftmtcmd_error; | ||
1300 | for (i = 0; i < ftcmd->ft_parm_cnt; i++) { | ||
1301 | TRACE_CATCH(ftape_parameter(ftcmd->ft_parms[i]&0x0f),); | ||
1302 | if (ftcmd->ft_status & QIC_STATUS_ERROR) | ||
1303 | goto ftmtcmd_error; | ||
1304 | } | ||
1305 | } | ||
1306 | if (ftcmd->ft_wait_after != 0) { | ||
1307 | TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_after, | ||
1308 | &ftcmd->ft_status),); | ||
1309 | } | ||
1310 | ftmtcmd_error: | ||
1311 | if (ftcmd->ft_status & QIC_STATUS_ERROR) { | ||
1312 | TRACE(ft_t_noise, "error status set"); | ||
1313 | TRACE_CATCH(ftape_report_error(&ftcmd->ft_error, | ||
1314 | &ftcmd->ft_cmd, 1),); | ||
1315 | } | ||
1316 | TRACE_EXIT 0; /* this is not an i/o error */ | ||
1317 | } | ||
1318 | #endif | ||
1319 | |||
1320 | /* IOCTL routine called by kernel-interface code | ||
1321 | */ | ||
1322 | int _zft_ioctl(unsigned int command, void __user * arg) | ||
1323 | { | ||
1324 | int result; | ||
1325 | union { struct mtop mtop; | ||
1326 | struct mtget mtget; | ||
1327 | struct mtpos mtpos; | ||
1328 | #ifdef MTIOCRDFTSEG | ||
1329 | struct mtftseg mtftseg; | ||
1330 | #endif | ||
1331 | #ifdef MTIOCVOLINFO | ||
1332 | struct mtvolinfo mtvolinfo; | ||
1333 | #endif | ||
1334 | #ifdef MTIOCGETSIZE | ||
1335 | struct mttapesize mttapesize; | ||
1336 | #endif | ||
1337 | #ifdef MTIOCFTFORMAT | ||
1338 | struct mtftformat mtftformat; | ||
1339 | #endif | ||
1340 | #ifdef ZFT_OBSOLETE | ||
1341 | struct mtblksz mtblksz; | ||
1342 | #endif | ||
1343 | #ifdef MTIOCFTCMD | ||
1344 | struct mtftcmd mtftcmd; | ||
1345 | #endif | ||
1346 | } krnl_arg; | ||
1347 | int arg_size = _IOC_SIZE(command); | ||
1348 | int dir = _IOC_DIR(command); | ||
1349 | TRACE_FUN(ft_t_flow); | ||
1350 | |||
1351 | /* This check will only catch arguments that are too large ! | ||
1352 | */ | ||
1353 | if (dir & (_IOC_READ | _IOC_WRITE) && arg_size > sizeof(krnl_arg)) { | ||
1354 | TRACE_ABORT(-EINVAL, | ||
1355 | ft_t_info, "bad argument size: %d", arg_size); | ||
1356 | } | ||
1357 | if (dir & _IOC_WRITE) { | ||
1358 | if (copy_from_user(&krnl_arg, arg, arg_size) != 0) { | ||
1359 | TRACE_EXIT -EFAULT; | ||
1360 | } | ||
1361 | } | ||
1362 | TRACE(ft_t_flow, "called with ioctl command: 0x%08x", command); | ||
1363 | switch (command) { | ||
1364 | case MTIOCTOP: | ||
1365 | result = mtioctop(&krnl_arg.mtop, arg_size); | ||
1366 | break; | ||
1367 | case MTIOCGET: | ||
1368 | result = mtiocget(&krnl_arg.mtget, arg_size); | ||
1369 | break; | ||
1370 | case MTIOCPOS: | ||
1371 | result = mtiocpos(&krnl_arg.mtpos, arg_size); | ||
1372 | break; | ||
1373 | #ifdef MTIOCVOLINFO | ||
1374 | case MTIOCVOLINFO: | ||
1375 | result = mtiocvolinfo(&krnl_arg.mtvolinfo, arg_size); | ||
1376 | break; | ||
1377 | #endif | ||
1378 | #ifdef ZFT_OBSOLETE | ||
1379 | case MTIOC_ZFTAPE_GETBLKSZ: | ||
1380 | result = mtioc_zftape_getblksz(&krnl_arg.mtblksz, arg_size); | ||
1381 | break; | ||
1382 | #endif | ||
1383 | #ifdef MTIOCRDFTSEG | ||
1384 | case MTIOCRDFTSEG: /* read a segment via ioctl */ | ||
1385 | result = mtiocrdftseg(&krnl_arg.mtftseg, arg_size); | ||
1386 | break; | ||
1387 | #endif | ||
1388 | #ifdef MTIOCWRFTSEG | ||
1389 | case MTIOCWRFTSEG: /* write a segment via ioctl */ | ||
1390 | result = mtiocwrftseg(&krnl_arg.mtftseg, arg_size); | ||
1391 | break; | ||
1392 | #endif | ||
1393 | #ifdef MTIOCGETSIZE | ||
1394 | case MTIOCGETSIZE: | ||
1395 | result = mtiocgetsize(&krnl_arg.mttapesize, arg_size); | ||
1396 | break; | ||
1397 | #endif | ||
1398 | #ifdef MTIOCFTFORMAT | ||
1399 | case MTIOCFTFORMAT: | ||
1400 | result = mtiocftformat(&krnl_arg.mtftformat, arg_size); | ||
1401 | break; | ||
1402 | #endif | ||
1403 | #ifdef MTIOCFTCMD | ||
1404 | case MTIOCFTCMD: | ||
1405 | result = mtiocftcmd(&krnl_arg.mtftcmd, arg_size); | ||
1406 | break; | ||
1407 | #endif | ||
1408 | default: | ||
1409 | result = -EINVAL; | ||
1410 | break; | ||
1411 | } | ||
1412 | if ((result >= 0) && (dir & _IOC_READ)) { | ||
1413 | if (copy_to_user(arg, &krnl_arg, arg_size) != 0) { | ||
1414 | TRACE_EXIT -EFAULT; | ||
1415 | } | ||
1416 | } | ||
1417 | TRACE_EXIT result; | ||
1418 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-ctl.h b/drivers/char/ftape/zftape/zftape-ctl.h new file mode 100644 index 000000000000..414159891990 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-ctl.h | |||
@@ -0,0 +1,59 @@ | |||
1 | #ifndef _ZFTAPE_CTL_H | ||
2 | #define _ZFTAPE_CTL_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus-Justus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-ctl.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:02 $ | ||
25 | * | ||
26 | * This file contains the non-standard IOCTL related definitions | ||
27 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
28 | */ | ||
29 | |||
30 | #include <linux/config.h> | ||
31 | #include <linux/ioctl.h> | ||
32 | #include <linux/mtio.h> | ||
33 | |||
34 | #include "../zftape/zftape-rw.h" | ||
35 | |||
36 | #ifdef CONFIG_ZFTAPE_MODULE | ||
37 | #define ftape_status (*zft_status) | ||
38 | #endif | ||
39 | |||
40 | extern int zft_offline; | ||
41 | extern int zft_mt_compression; | ||
42 | extern int zft_write_protected; | ||
43 | extern int zft_header_read; | ||
44 | extern unsigned int zft_unit; | ||
45 | extern int zft_resid; | ||
46 | |||
47 | extern void zft_reset_position(zft_position *pos); | ||
48 | extern int zft_check_write_access(zft_position *pos); | ||
49 | extern int zft_def_idle_state(void); | ||
50 | |||
51 | /* hooks for the VFS interface | ||
52 | */ | ||
53 | extern int _zft_open(unsigned int dev_minor, unsigned int access_mode); | ||
54 | extern int _zft_close(void); | ||
55 | extern int _zft_ioctl(unsigned int command, void __user *arg); | ||
56 | #endif | ||
57 | |||
58 | |||
59 | |||
diff --git a/drivers/char/ftape/zftape/zftape-eof.c b/drivers/char/ftape/zftape/zftape-eof.c new file mode 100644 index 000000000000..dcadcaee9ac1 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-eof.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * I use these routines just to decide when I have to fake a | ||
3 | * volume-table to preserve compatibility to original ftape. | ||
4 | */ | ||
5 | /* | ||
6 | * Copyright (C) 1994-1995 Bas Laarhoven. | ||
7 | * | ||
8 | * Modified for zftape 1996, 1997 Claus Heine. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2, or (at your option) | ||
13 | any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; see the file COPYING. If not, write to | ||
22 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | |||
24 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.c,v $ | ||
25 | * $Revision: 1.2 $ | ||
26 | * $Date: 1997/10/05 19:19:02 $ | ||
27 | * | ||
28 | * This file contains the eof mark handling code | ||
29 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
30 | */ | ||
31 | |||
32 | #include <linux/string.h> | ||
33 | #include <linux/errno.h> | ||
34 | |||
35 | #include <linux/zftape.h> | ||
36 | |||
37 | #include "../zftape/zftape-init.h" | ||
38 | #include "../zftape/zftape-rw.h" | ||
39 | #include "../zftape/zftape-eof.h" | ||
40 | |||
41 | /* Global vars. | ||
42 | */ | ||
43 | |||
44 | /* a copy of the failed sector log from the header segment. | ||
45 | */ | ||
46 | eof_mark_union *zft_eof_map; | ||
47 | |||
48 | /* number of eof marks (entries in bad sector log) on tape. | ||
49 | */ | ||
50 | int zft_nr_eof_marks = -1; | ||
51 | |||
52 | |||
53 | /* Local vars. | ||
54 | */ | ||
55 | |||
56 | static char linux_tape_label[] = "Linux raw format V"; | ||
57 | enum { | ||
58 | min_fmt_version = 1, max_fmt_version = 2 | ||
59 | }; | ||
60 | static unsigned ftape_fmt_version = 0; | ||
61 | |||
62 | |||
63 | /* Ftape (mis)uses the bad sector log to record end-of-file marks. | ||
64 | * Initially (when the tape is erased) all entries in the bad sector | ||
65 | * log are added to the tape's bad sector map. The bad sector log then | ||
66 | * is cleared. | ||
67 | * | ||
68 | * The bad sector log normally contains entries of the form: | ||
69 | * even 16-bit word: segment number of bad sector | ||
70 | * odd 16-bit word: encoded date | ||
71 | * There can be a total of 448 entries (1792 bytes). | ||
72 | * | ||
73 | * My guess is that no program is using this bad sector log (the * | ||
74 | * format seems useless as there is no indication of the bad sector | ||
75 | * itself, only the segment) However, if any program does use the bad | ||
76 | * sector log, the format used by ftape will let the program think | ||
77 | * there are some bad sectors and no harm is done. | ||
78 | * | ||
79 | * The eof mark entries that ftape stores in the bad sector log: even | ||
80 | * 16-bit word: segment number of eof mark odd 16-bit word: sector | ||
81 | * number of eof mark [1..32] | ||
82 | * | ||
83 | * The zft_eof_map as maintained is a sorted list of eof mark entries. | ||
84 | * | ||
85 | * | ||
86 | * The tape name field in the header segments is used to store a linux | ||
87 | * tape identification string and a version number. This way the tape | ||
88 | * can be recognized as a Linux raw format tape when using tools under | ||
89 | * other OS's. | ||
90 | * | ||
91 | * 'Wide' QIC tapes (format code 4) don't have a failed sector list | ||
92 | * anymore. That space is used for the (longer) bad sector map that | ||
93 | * now is a variable length list too. We now store our end-of-file | ||
94 | * marker list after the bad-sector-map on tape. The list is delimited | ||
95 | * by a (__u32) 0 entry. | ||
96 | */ | ||
97 | |||
98 | int zft_ftape_validate_label(char *label) | ||
99 | { | ||
100 | static char tmp_label[45]; | ||
101 | int result = 0; | ||
102 | TRACE_FUN(ft_t_any); | ||
103 | |||
104 | memcpy(tmp_label, label, FT_LABEL_SZ); | ||
105 | tmp_label[FT_LABEL_SZ] = '\0'; | ||
106 | TRACE(ft_t_noise, "tape label = `%s'", tmp_label); | ||
107 | ftape_fmt_version = 0; | ||
108 | if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) { | ||
109 | int pos = strlen(linux_tape_label); | ||
110 | while (label[pos] >= '0' && label[pos] <= '9') { | ||
111 | ftape_fmt_version *= 10; | ||
112 | ftape_fmt_version = label[ pos++] - '0'; | ||
113 | } | ||
114 | result = (ftape_fmt_version >= min_fmt_version && | ||
115 | ftape_fmt_version <= max_fmt_version); | ||
116 | } | ||
117 | TRACE(ft_t_noise, "format version = %d", ftape_fmt_version); | ||
118 | TRACE_EXIT result; | ||
119 | } | ||
120 | |||
121 | static __u8 * find_end_of_eof_list(__u8 * ptr, __u8 * limit) | ||
122 | { | ||
123 | while (ptr + 3 < limit) { | ||
124 | |||
125 | if (get_unaligned((__u32*)ptr)) { | ||
126 | ptr += sizeof(__u32); | ||
127 | } else { | ||
128 | return ptr; | ||
129 | } | ||
130 | } | ||
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | void zft_ftape_extract_file_marks(__u8* address) | ||
135 | { | ||
136 | int i; | ||
137 | TRACE_FUN(ft_t_any); | ||
138 | |||
139 | zft_eof_map = NULL; | ||
140 | if (ft_format_code == fmt_var || ft_format_code == fmt_big) { | ||
141 | __u8* end; | ||
142 | __u8* start = ftape_find_end_of_bsm_list(address); | ||
143 | |||
144 | zft_nr_eof_marks = 0; | ||
145 | if (start) { | ||
146 | start += 3; /* skip end of list mark */ | ||
147 | end = find_end_of_eof_list(start, | ||
148 | address + FT_SEGMENT_SIZE); | ||
149 | if (end && end - start <= FT_FSL_SIZE) { | ||
150 | zft_nr_eof_marks = ((end - start) / | ||
151 | sizeof(eof_mark_union)); | ||
152 | zft_eof_map = (eof_mark_union *)start; | ||
153 | } else { | ||
154 | TRACE(ft_t_err, | ||
155 | "EOF Mark List is too long or damaged!"); | ||
156 | } | ||
157 | } else { | ||
158 | TRACE(ft_t_err, | ||
159 | "Bad Sector List is too long or damaged !"); | ||
160 | } | ||
161 | } else { | ||
162 | zft_eof_map = (eof_mark_union *)&address[FT_FSL]; | ||
163 | zft_nr_eof_marks = GET2(address, FT_FSL_CNT); | ||
164 | } | ||
165 | TRACE(ft_t_noise, "number of file marks: %d", zft_nr_eof_marks); | ||
166 | if (ftape_fmt_version == 1) { | ||
167 | TRACE(ft_t_info, "swapping version 1 fields"); | ||
168 | /* version 1 format uses swapped sector and segment | ||
169 | * fields, correct that ! | ||
170 | */ | ||
171 | for (i = 0; i < zft_nr_eof_marks; ++i) { | ||
172 | __u16 tmp = GET2(&zft_eof_map[i].mark.segment,0); | ||
173 | PUT2(&zft_eof_map[i].mark.segment, 0, | ||
174 | GET2(&zft_eof_map[i].mark.date,0)); | ||
175 | PUT2(&zft_eof_map[i].mark.date, 0, tmp); | ||
176 | } | ||
177 | } | ||
178 | for (i = 0; i < zft_nr_eof_marks; ++i) { | ||
179 | TRACE(ft_t_noise, "eof mark: %5d/%2d", | ||
180 | GET2(&zft_eof_map[i].mark.segment, 0), | ||
181 | GET2(&zft_eof_map[i].mark.date,0)); | ||
182 | } | ||
183 | TRACE_EXIT; | ||
184 | } | ||
185 | |||
186 | void zft_clear_ftape_file_marks(void) | ||
187 | { | ||
188 | TRACE_FUN(ft_t_flow); | ||
189 | /* Clear failed sector log: remove all tape marks. We | ||
190 | * don't use old ftape-style EOF-marks. | ||
191 | */ | ||
192 | TRACE(ft_t_info, "Clearing old ftape's eof map"); | ||
193 | memset(zft_eof_map, 0, zft_nr_eof_marks * sizeof(__u32)); | ||
194 | zft_nr_eof_marks = 0; | ||
195 | PUT2(zft_hseg_buf, FT_FSL_CNT, 0); /* nr of eof-marks */ | ||
196 | zft_header_changed = 1; | ||
197 | zft_update_label(zft_hseg_buf); | ||
198 | TRACE_EXIT; | ||
199 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-eof.h b/drivers/char/ftape/zftape/zftape-eof.h new file mode 100644 index 000000000000..26568c26c518 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-eof.h | |||
@@ -0,0 +1,52 @@ | |||
1 | #ifndef _ZFTAPE_EOF_H | ||
2 | #define _ZFTAPE_EOF_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1995 Bas Laarhoven. | ||
6 | * adaptaed for zftape 1996, 1997 by Claus Heine | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:19:03 $ | ||
26 | * | ||
27 | * Definitions and declarations for the end of file markers | ||
28 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
29 | */ | ||
30 | |||
31 | #include <linux/ftape-header-segment.h> | ||
32 | #include "../zftape/zftape-buffers.h" | ||
33 | /* failed sector log size (only used if format code != 4). | ||
34 | */ | ||
35 | |||
36 | typedef union { | ||
37 | ft_fsl_entry mark; | ||
38 | __u32 entry; | ||
39 | } eof_mark_union; | ||
40 | |||
41 | /* ftape-eof.c defined global vars. | ||
42 | */ | ||
43 | extern int zft_nr_eof_marks; | ||
44 | extern eof_mark_union *zft_eof_map; | ||
45 | |||
46 | /* ftape-eof.c defined global functions. | ||
47 | */ | ||
48 | extern void zft_ftape_extract_file_marks(__u8* address); | ||
49 | extern int zft_ftape_validate_label(char* label); | ||
50 | extern void zft_clear_ftape_file_marks(void); | ||
51 | |||
52 | #endif | ||
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c new file mode 100644 index 000000000000..dbac7e54e8e0 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-init.c | |||
@@ -0,0 +1,403 @@ | |||
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/fs.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/signal.h> | ||
29 | #include <linux/major.h> | ||
30 | #include <linux/slab.h> | ||
31 | #ifdef CONFIG_KMOD | ||
32 | #include <linux/kmod.h> | ||
33 | #endif | ||
34 | #include <linux/fcntl.h> | ||
35 | #include <linux/smp_lock.h> | ||
36 | #include <linux/devfs_fs_kernel.h> | ||
37 | |||
38 | #include <linux/zftape.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/device.h> | ||
41 | |||
42 | #include "../zftape/zftape-init.h" | ||
43 | #include "../zftape/zftape-read.h" | ||
44 | #include "../zftape/zftape-write.h" | ||
45 | #include "../zftape/zftape-ctl.h" | ||
46 | #include "../zftape/zftape-buffers.h" | ||
47 | |||
48 | MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine " | ||
49 | "(claus@momo.math.rwth-aachen.de)"); | ||
50 | MODULE_DESCRIPTION(ZFTAPE_VERSION " - " | ||
51 | "VFS interface for the Linux floppy tape driver. " | ||
52 | "Support for QIC-113 compatible volume table " | ||
53 | "and builtin compression (lzrw3 algorithm)"); | ||
54 | MODULE_SUPPORTED_DEVICE("char-major-27"); | ||
55 | MODULE_LICENSE("GPL"); | ||
56 | |||
57 | /* Global vars. | ||
58 | */ | ||
59 | struct zft_cmpr_ops *zft_cmpr_ops = NULL; | ||
60 | const ftape_info *zft_status; | ||
61 | |||
62 | /* Local vars. | ||
63 | */ | ||
64 | static unsigned long busy_flag; | ||
65 | |||
66 | static sigset_t orig_sigmask; | ||
67 | |||
68 | /* the interface to the kernel vfs layer | ||
69 | */ | ||
70 | |||
71 | /* Note about llseek(): | ||
72 | * | ||
73 | * st.c and tpqic.c update fp->f_pos but don't implment llseek() and | ||
74 | * initialize the llseek component of the file_ops struct with NULL. | ||
75 | * This means that the user will get the default seek, but the tape | ||
76 | * device will not respect the new position, but happily read from the | ||
77 | * old position. Think a zftape specific llseek() function would be | ||
78 | * better, returning -ESPIPE. TODO. | ||
79 | */ | ||
80 | |||
81 | static int zft_open (struct inode *ino, struct file *filep); | ||
82 | static int zft_close(struct inode *ino, struct file *filep); | ||
83 | static int zft_ioctl(struct inode *ino, struct file *filep, | ||
84 | unsigned int command, unsigned long arg); | ||
85 | static int zft_mmap(struct file *filep, struct vm_area_struct *vma); | ||
86 | static ssize_t zft_read (struct file *fp, char __user *buff, | ||
87 | size_t req_len, loff_t *ppos); | ||
88 | static ssize_t zft_write(struct file *fp, const char __user *buff, | ||
89 | size_t req_len, loff_t *ppos); | ||
90 | |||
91 | static struct file_operations zft_cdev = | ||
92 | { | ||
93 | .owner = THIS_MODULE, | ||
94 | .read = zft_read, | ||
95 | .write = zft_write, | ||
96 | .ioctl = zft_ioctl, | ||
97 | .mmap = zft_mmap, | ||
98 | .open = zft_open, | ||
99 | .release = zft_close, | ||
100 | }; | ||
101 | |||
102 | static struct class_simple *zft_class; | ||
103 | |||
104 | /* Open floppy tape device | ||
105 | */ | ||
106 | static int zft_open(struct inode *ino, struct file *filep) | ||
107 | { | ||
108 | int result; | ||
109 | TRACE_FUN(ft_t_flow); | ||
110 | |||
111 | nonseekable_open(ino, filep); | ||
112 | TRACE(ft_t_flow, "called for minor %d", iminor(ino)); | ||
113 | if ( test_and_set_bit(0,&busy_flag) ) { | ||
114 | TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy"); | ||
115 | } | ||
116 | if ((iminor(ino) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND)) | ||
117 | > | ||
118 | FTAPE_SEL_D) { | ||
119 | clear_bit(0,&busy_flag); | ||
120 | TRACE_ABORT(-ENXIO, ft_t_err, "failed: invalid unit nr"); | ||
121 | } | ||
122 | orig_sigmask = current->blocked; | ||
123 | sigfillset(¤t->blocked); | ||
124 | result = _zft_open(iminor(ino), filep->f_flags & O_ACCMODE); | ||
125 | if (result < 0) { | ||
126 | current->blocked = orig_sigmask; /* restore mask */ | ||
127 | clear_bit(0,&busy_flag); | ||
128 | TRACE_ABORT(result, ft_t_err, "_ftape_open failed"); | ||
129 | } else { | ||
130 | /* Mask signals that will disturb proper operation of the | ||
131 | * program that is calling. | ||
132 | */ | ||
133 | current->blocked = orig_sigmask; | ||
134 | sigaddsetmask (¤t->blocked, _DO_BLOCK); | ||
135 | TRACE_EXIT 0; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | /* Close floppy tape device | ||
140 | */ | ||
141 | static int zft_close(struct inode *ino, struct file *filep) | ||
142 | { | ||
143 | int result; | ||
144 | TRACE_FUN(ft_t_flow); | ||
145 | |||
146 | if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit) { | ||
147 | TRACE(ft_t_err, "failed: not busy or wrong unit"); | ||
148 | TRACE_EXIT 0; | ||
149 | } | ||
150 | sigfillset(¤t->blocked); | ||
151 | result = _zft_close(); | ||
152 | if (result < 0) { | ||
153 | TRACE(ft_t_err, "_zft_close failed"); | ||
154 | } | ||
155 | current->blocked = orig_sigmask; /* restore before open state */ | ||
156 | clear_bit(0,&busy_flag); | ||
157 | TRACE_EXIT 0; | ||
158 | } | ||
159 | |||
160 | /* Ioctl for floppy tape device | ||
161 | */ | ||
162 | static int zft_ioctl(struct inode *ino, struct file *filep, | ||
163 | unsigned int command, unsigned long arg) | ||
164 | { | ||
165 | int result = -EIO; | ||
166 | sigset_t old_sigmask; | ||
167 | TRACE_FUN(ft_t_flow); | ||
168 | |||
169 | if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { | ||
170 | TRACE_ABORT(-EIO, ft_t_err, | ||
171 | "failed: not busy, failure or wrong unit"); | ||
172 | } | ||
173 | old_sigmask = current->blocked; /* save mask */ | ||
174 | sigfillset(¤t->blocked); | ||
175 | /* This will work as long as sizeof(void *) == sizeof(long) */ | ||
176 | result = _zft_ioctl(command, (void __user *) arg); | ||
177 | current->blocked = old_sigmask; /* restore mask */ | ||
178 | TRACE_EXIT result; | ||
179 | } | ||
180 | |||
181 | /* Ioctl for floppy tape device | ||
182 | */ | ||
183 | static int zft_mmap(struct file *filep, struct vm_area_struct *vma) | ||
184 | { | ||
185 | int result = -EIO; | ||
186 | sigset_t old_sigmask; | ||
187 | TRACE_FUN(ft_t_flow); | ||
188 | |||
189 | if ( !test_bit(0,&busy_flag) || | ||
190 | iminor(filep->f_dentry->d_inode) != zft_unit || | ||
191 | ft_failure) | ||
192 | { | ||
193 | TRACE_ABORT(-EIO, ft_t_err, | ||
194 | "failed: not busy, failure or wrong unit"); | ||
195 | } | ||
196 | old_sigmask = current->blocked; /* save mask */ | ||
197 | sigfillset(¤t->blocked); | ||
198 | if ((result = ftape_mmap(vma)) >= 0) { | ||
199 | #ifndef MSYNC_BUG_WAS_FIXED | ||
200 | static struct vm_operations_struct dummy = { NULL, }; | ||
201 | vma->vm_ops = &dummy; | ||
202 | #endif | ||
203 | } | ||
204 | current->blocked = old_sigmask; /* restore mask */ | ||
205 | TRACE_EXIT result; | ||
206 | } | ||
207 | |||
208 | /* Read from floppy tape device | ||
209 | */ | ||
210 | static ssize_t zft_read(struct file *fp, char __user *buff, | ||
211 | size_t req_len, loff_t *ppos) | ||
212 | { | ||
213 | int result = -EIO; | ||
214 | sigset_t old_sigmask; | ||
215 | struct inode *ino = fp->f_dentry->d_inode; | ||
216 | TRACE_FUN(ft_t_flow); | ||
217 | |||
218 | TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len); | ||
219 | if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { | ||
220 | TRACE_ABORT(-EIO, ft_t_err, | ||
221 | "failed: not busy, failure or wrong unit"); | ||
222 | } | ||
223 | old_sigmask = current->blocked; /* save mask */ | ||
224 | sigfillset(¤t->blocked); | ||
225 | result = _zft_read(buff, req_len); | ||
226 | current->blocked = old_sigmask; /* restore mask */ | ||
227 | TRACE(ft_t_data_flow, "return with count: %d", result); | ||
228 | TRACE_EXIT result; | ||
229 | } | ||
230 | |||
231 | /* Write to tape device | ||
232 | */ | ||
233 | static ssize_t zft_write(struct file *fp, const char __user *buff, | ||
234 | size_t req_len, loff_t *ppos) | ||
235 | { | ||
236 | int result = -EIO; | ||
237 | sigset_t old_sigmask; | ||
238 | struct inode *ino = fp->f_dentry->d_inode; | ||
239 | TRACE_FUN(ft_t_flow); | ||
240 | |||
241 | TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len); | ||
242 | if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { | ||
243 | TRACE_ABORT(-EIO, ft_t_err, | ||
244 | "failed: not busy, failure or wrong unit"); | ||
245 | } | ||
246 | old_sigmask = current->blocked; /* save mask */ | ||
247 | sigfillset(¤t->blocked); | ||
248 | result = _zft_write(buff, req_len); | ||
249 | current->blocked = old_sigmask; /* restore mask */ | ||
250 | TRACE(ft_t_data_flow, "return with count: %d", result); | ||
251 | TRACE_EXIT result; | ||
252 | } | ||
253 | |||
254 | /* END OF VFS INTERFACE | ||
255 | * | ||
256 | *****************************************************************************/ | ||
257 | |||
258 | /* driver/module initialization | ||
259 | */ | ||
260 | |||
261 | /* the compression module has to call this function to hook into the zftape | ||
262 | * code | ||
263 | */ | ||
264 | int zft_cmpr_register(struct zft_cmpr_ops *new_ops) | ||
265 | { | ||
266 | TRACE_FUN(ft_t_flow); | ||
267 | |||
268 | if (zft_cmpr_ops != NULL) { | ||
269 | TRACE_EXIT -EBUSY; | ||
270 | } else { | ||
271 | zft_cmpr_ops = new_ops; | ||
272 | TRACE_EXIT 0; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | /* lock the zft-compressor() module. | ||
277 | */ | ||
278 | int zft_cmpr_lock(int try_to_load) | ||
279 | { | ||
280 | if (zft_cmpr_ops == NULL) { | ||
281 | #ifdef CONFIG_KMOD | ||
282 | if (try_to_load) { | ||
283 | request_module("zft-compressor"); | ||
284 | if (zft_cmpr_ops == NULL) { | ||
285 | return -ENOSYS; | ||
286 | } | ||
287 | } else { | ||
288 | return -ENOSYS; | ||
289 | } | ||
290 | #else | ||
291 | return -ENOSYS; | ||
292 | #endif | ||
293 | } | ||
294 | (*zft_cmpr_ops->lock)(); | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | #ifdef CONFIG_ZFT_COMPRESSOR | ||
299 | extern int zft_compressor_init(void); | ||
300 | #endif | ||
301 | |||
302 | /* Called by modules package when installing the driver or by kernel | ||
303 | * during the initialization phase | ||
304 | */ | ||
305 | int __init zft_init(void) | ||
306 | { | ||
307 | int i; | ||
308 | TRACE_FUN(ft_t_flow); | ||
309 | |||
310 | #ifdef MODULE | ||
311 | printk(KERN_INFO ZFTAPE_VERSION "\n"); | ||
312 | if (TRACE_LEVEL >= ft_t_info) { | ||
313 | printk( | ||
314 | KERN_INFO | ||
315 | "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" | ||
316 | KERN_INFO | ||
317 | "vfs interface for ftape floppy tape driver.\n" | ||
318 | KERN_INFO | ||
319 | "Support for QIC-113 compatible volume table, dynamic memory allocation\n" | ||
320 | KERN_INFO | ||
321 | "and builtin compression (lzrw3 algorithm).\n"); | ||
322 | } | ||
323 | #else /* !MODULE */ | ||
324 | /* print a short no-nonsense boot message */ | ||
325 | printk(KERN_INFO ZFTAPE_VERSION "\n"); | ||
326 | #endif /* MODULE */ | ||
327 | TRACE(ft_t_info, "zft_init @ 0x%p", zft_init); | ||
328 | TRACE(ft_t_info, | ||
329 | "installing zftape VFS interface for ftape driver ..."); | ||
330 | TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); | ||
331 | |||
332 | zft_class = class_simple_create(THIS_MODULE, "zft"); | ||
333 | for (i = 0; i < 4; i++) { | ||
334 | class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); | ||
335 | devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i), | ||
336 | S_IFCHR | S_IRUSR | S_IWUSR, | ||
337 | "qft%i", i); | ||
338 | class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); | ||
339 | devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4), | ||
340 | S_IFCHR | S_IRUSR | S_IWUSR, | ||
341 | "nqft%i", i); | ||
342 | class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); | ||
343 | devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16), | ||
344 | S_IFCHR | S_IRUSR | S_IWUSR, | ||
345 | "zqft%i", i); | ||
346 | class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); | ||
347 | devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20), | ||
348 | S_IFCHR | S_IRUSR | S_IWUSR, | ||
349 | "nzqft%i", i); | ||
350 | class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); | ||
351 | devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32), | ||
352 | S_IFCHR | S_IRUSR | S_IWUSR, | ||
353 | "rawqft%i", i); | ||
354 | class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); | ||
355 | devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36), | ||
356 | S_IFCHR | S_IRUSR | S_IWUSR, | ||
357 | "nrawqft%i", i); | ||
358 | } | ||
359 | |||
360 | #ifdef CONFIG_ZFT_COMPRESSOR | ||
361 | (void)zft_compressor_init(); | ||
362 | #endif | ||
363 | zft_status = ftape_get_status(); /* fetch global data of ftape | ||
364 | * hardware driver | ||
365 | */ | ||
366 | TRACE_EXIT 0; | ||
367 | } | ||
368 | |||
369 | |||
370 | /* Called by modules package when removing the driver | ||
371 | */ | ||
372 | static void zft_exit(void) | ||
373 | { | ||
374 | int i; | ||
375 | TRACE_FUN(ft_t_flow); | ||
376 | |||
377 | if (unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) { | ||
378 | TRACE(ft_t_warn, "failed"); | ||
379 | } else { | ||
380 | TRACE(ft_t_info, "successful"); | ||
381 | } | ||
382 | for (i = 0; i < 4; i++) { | ||
383 | devfs_remove("qft%i", i); | ||
384 | class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i)); | ||
385 | devfs_remove("nqft%i", i); | ||
386 | class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 4)); | ||
387 | devfs_remove("zqft%i", i); | ||
388 | class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 16)); | ||
389 | devfs_remove("nzqft%i", i); | ||
390 | class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 20)); | ||
391 | devfs_remove("rawqft%i", i); | ||
392 | class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 32)); | ||
393 | devfs_remove("nrawqft%i", i); | ||
394 | class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 36)); | ||
395 | } | ||
396 | class_simple_destroy(zft_class); | ||
397 | zft_uninit_mem(); /* release remaining memory, if any */ | ||
398 | printk(KERN_INFO "zftape successfully unloaded.\n"); | ||
399 | TRACE_EXIT; | ||
400 | } | ||
401 | |||
402 | module_init(zft_init); | ||
403 | module_exit(zft_exit); | ||
diff --git a/drivers/char/ftape/zftape/zftape-init.h b/drivers/char/ftape/zftape/zftape-init.h new file mode 100644 index 000000000000..937e5d48c20e --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-init.h | |||
@@ -0,0 +1,77 @@ | |||
1 | #ifndef _ZFTAPE_INIT_H | ||
2 | #define _ZFTAPE_INIT_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-init.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:05 $ | ||
25 | * | ||
26 | * This file contains definitions and macro for the vfs | ||
27 | * interface defined by zftape | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/ftape-header-segment.h> | ||
32 | |||
33 | #include "../lowlevel/ftape-tracing.h" | ||
34 | #include "../lowlevel/ftape-ctl.h" | ||
35 | #include "../lowlevel/ftape-read.h" | ||
36 | #include "../lowlevel/ftape-write.h" | ||
37 | #include "../lowlevel/ftape-bsm.h" | ||
38 | #include "../lowlevel/ftape-io.h" | ||
39 | #include "../lowlevel/ftape-buffer.h" | ||
40 | #include "../lowlevel/ftape-format.h" | ||
41 | |||
42 | #include "../zftape/zftape-rw.h" | ||
43 | |||
44 | #ifdef MODULE | ||
45 | #define ftape_status (*zft_status) | ||
46 | #endif | ||
47 | |||
48 | extern const ftape_info *zft_status; /* needed for zftape-vtbl.h */ | ||
49 | |||
50 | #include "../zftape/zftape-vtbl.h" | ||
51 | |||
52 | struct zft_cmpr_ops { | ||
53 | int (*write)(int *write_cnt, | ||
54 | __u8 *dst_buf, const int seg_sz, | ||
55 | const __u8 __user *src_buf, const int req_len, | ||
56 | const zft_position *pos, const zft_volinfo *volume); | ||
57 | int (*read)(int *read_cnt, | ||
58 | __u8 __user *dst_buf, const int req_len, | ||
59 | const __u8 *src_buf, const int seg_sz, | ||
60 | const zft_position *pos, const zft_volinfo *volume); | ||
61 | int (*seek)(unsigned int new_block_pos, | ||
62 | zft_position *pos, const zft_volinfo *volume, | ||
63 | __u8 *buffer); | ||
64 | void (*lock) (void); | ||
65 | void (*reset) (void); | ||
66 | void (*cleanup)(void); | ||
67 | }; | ||
68 | |||
69 | extern struct zft_cmpr_ops *zft_cmpr_ops; | ||
70 | /* zftape-init.c defined global functions. | ||
71 | */ | ||
72 | extern int zft_cmpr_register(struct zft_cmpr_ops *new_ops); | ||
73 | extern int zft_cmpr_lock(int try_to_load); | ||
74 | |||
75 | #endif | ||
76 | |||
77 | |||
diff --git a/drivers/char/ftape/zftape/zftape-read.c b/drivers/char/ftape/zftape/zftape-read.c new file mode 100644 index 000000000000..214bf03dce68 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-read.c | |||
@@ -0,0 +1,377 @@ | |||
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 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-read.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:19:06 $ | ||
22 | * | ||
23 | * This file contains the high level reading code | ||
24 | * for the QIC-117 floppy-tape driver for Linux. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | |||
30 | #include <linux/zftape.h> | ||
31 | |||
32 | #include <asm/uaccess.h> | ||
33 | |||
34 | #include "../zftape/zftape-init.h" | ||
35 | #include "../zftape/zftape-eof.h" | ||
36 | #include "../zftape/zftape-ctl.h" | ||
37 | #include "../zftape/zftape-write.h" | ||
38 | #include "../zftape/zftape-read.h" | ||
39 | #include "../zftape/zftape-rw.h" | ||
40 | #include "../zftape/zftape-vtbl.h" | ||
41 | |||
42 | /* Global vars. | ||
43 | */ | ||
44 | int zft_just_before_eof; | ||
45 | |||
46 | /* Local vars. | ||
47 | */ | ||
48 | static int buf_len_rd; | ||
49 | |||
50 | void zft_zap_read_buffers(void) | ||
51 | { | ||
52 | buf_len_rd = 0; | ||
53 | } | ||
54 | |||
55 | int zft_read_header_segments(void) | ||
56 | { | ||
57 | TRACE_FUN(ft_t_flow); | ||
58 | |||
59 | zft_header_read = 0; | ||
60 | TRACE_CATCH(zft_vmalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); | ||
61 | TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),); | ||
62 | TRACE(ft_t_info, "Segments written since first format: %d", | ||
63 | (int)GET4(zft_hseg_buf, FT_SEG_CNT)); | ||
64 | zft_qic113 = (ft_format_code != fmt_normal && | ||
65 | ft_format_code != fmt_1100ft && | ||
66 | ft_format_code != fmt_425ft); | ||
67 | TRACE(ft_t_info, "ft_first_data_segment: %d, ft_last_data_segment: %d", | ||
68 | ft_first_data_segment, ft_last_data_segment); | ||
69 | zft_capacity = zft_get_capacity(); | ||
70 | zft_old_ftape = zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]); | ||
71 | if (zft_old_ftape) { | ||
72 | TRACE(ft_t_info, | ||
73 | "Found old ftaped tape, emulating eof marks, entering read-only mode"); | ||
74 | zft_ftape_extract_file_marks(zft_hseg_buf); | ||
75 | TRACE_CATCH(zft_fake_volume_headers(zft_eof_map, | ||
76 | zft_nr_eof_marks),); | ||
77 | } else { | ||
78 | /* the specs say that the volume table must be | ||
79 | * initialized with zeroes during formatting, so it | ||
80 | * MUST be readable, i.e. contain vaid ECC | ||
81 | * information. | ||
82 | */ | ||
83 | TRACE_CATCH(ftape_read_segment(ft_first_data_segment, | ||
84 | zft_deblock_buf, | ||
85 | FT_RD_SINGLE),); | ||
86 | TRACE_CATCH(zft_extract_volume_headers(zft_deblock_buf),); | ||
87 | } | ||
88 | zft_header_read = 1; | ||
89 | zft_set_flags(zft_unit); | ||
90 | zft_reset_position(&zft_pos); | ||
91 | TRACE_EXIT 0; | ||
92 | } | ||
93 | |||
94 | int zft_fetch_segment_fraction(const unsigned int segment, void *buffer, | ||
95 | const ft_read_mode_t read_mode, | ||
96 | const unsigned int start, | ||
97 | const unsigned int size) | ||
98 | { | ||
99 | int seg_sz; | ||
100 | TRACE_FUN(ft_t_flow); | ||
101 | |||
102 | if (segment == zft_deblock_segment) { | ||
103 | TRACE(ft_t_data_flow, | ||
104 | "re-using segment %d already in deblock buffer", | ||
105 | segment); | ||
106 | seg_sz = zft_get_seg_sz(segment); | ||
107 | if (start > seg_sz) { | ||
108 | TRACE_ABORT(-EINVAL, ft_t_bug, | ||
109 | "trying to read beyond end of segment:\n" | ||
110 | KERN_INFO "seg_sz : %d\n" | ||
111 | KERN_INFO "start : %d\n" | ||
112 | KERN_INFO "segment: %d", | ||
113 | seg_sz, start, segment); | ||
114 | } | ||
115 | if ((start + size) > seg_sz) { | ||
116 | TRACE_EXIT seg_sz - start; | ||
117 | } | ||
118 | TRACE_EXIT size; | ||
119 | } | ||
120 | seg_sz = ftape_read_segment_fraction(segment, buffer, read_mode, | ||
121 | start, size); | ||
122 | TRACE(ft_t_data_flow, "segment %d, result %d", segment, seg_sz); | ||
123 | if ((int)seg_sz >= 0 && start == 0 && size == FT_SEGMENT_SIZE) { | ||
124 | /* this implicitly assumes that we are always called with | ||
125 | * buffer == zft_deblock_buf | ||
126 | */ | ||
127 | zft_deblock_segment = segment; | ||
128 | } else { | ||
129 | zft_deblock_segment = -1; | ||
130 | } | ||
131 | TRACE_EXIT seg_sz; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * out: | ||
136 | * | ||
137 | * int *read_cnt: the number of bytes we removed from the | ||
138 | * zft_deblock_buf (result) | ||
139 | * | ||
140 | * int *to_do : the remaining size of the read-request. Is changed. | ||
141 | * | ||
142 | * in: | ||
143 | * | ||
144 | * char *buff : buff is the address of the upper part of the user | ||
145 | * buffer, that hasn't been filled with data yet. | ||
146 | * int buf_pos_read: copy of buf_pos_rd | ||
147 | * int buf_len_read: copy of buf_len_rd | ||
148 | * char *zft_deblock_buf: ftape_zft_deblock_buf | ||
149 | * | ||
150 | * returns the amount of data actually copied to the user-buffer | ||
151 | * | ||
152 | * to_do MUST NOT SHRINK except to indicate an EOT. In this case to_do | ||
153 | * has to be set to 0. We cannot return -ENOSPC, because we return the | ||
154 | * amount of data actually * copied to the user-buffer | ||
155 | */ | ||
156 | static int zft_simple_read (int *read_cnt, | ||
157 | __u8 __user *dst_buf, | ||
158 | const int to_do, | ||
159 | const __u8 *src_buf, | ||
160 | const int seg_sz, | ||
161 | const zft_position *pos, | ||
162 | const zft_volinfo *volume) | ||
163 | { | ||
164 | TRACE_FUN(ft_t_flow); | ||
165 | |||
166 | if (seg_sz - pos->seg_byte_pos < to_do) { | ||
167 | *read_cnt = seg_sz - pos->seg_byte_pos; | ||
168 | } else { | ||
169 | *read_cnt = to_do; | ||
170 | } | ||
171 | if (copy_to_user(dst_buf, | ||
172 | src_buf + pos->seg_byte_pos, *read_cnt) != 0) { | ||
173 | TRACE_EXIT -EFAULT; | ||
174 | } | ||
175 | TRACE(ft_t_noise, "nr bytes just read: %d", *read_cnt); | ||
176 | TRACE_EXIT *read_cnt; | ||
177 | } | ||
178 | |||
179 | /* req_len: gets clipped due to EOT of EOF. | ||
180 | * req_clipped: is a flag indicating whether req_len was clipped or not | ||
181 | * volume: contains information on current volume (blk_sz etc.) | ||
182 | */ | ||
183 | static int check_read_access(int *req_len, | ||
184 | const zft_volinfo **volume, | ||
185 | int *req_clipped, | ||
186 | const zft_position *pos) | ||
187 | { | ||
188 | static __s64 remaining; | ||
189 | static int eod; | ||
190 | TRACE_FUN(ft_t_flow); | ||
191 | |||
192 | if (zft_io_state != zft_reading) { | ||
193 | if (zft_offline) { /* offline includes no_tape */ | ||
194 | TRACE_ABORT(-ENXIO, ft_t_warn, | ||
195 | "tape is offline or no cartridge"); | ||
196 | } | ||
197 | if (!ft_formatted) { | ||
198 | TRACE_ABORT(-EACCES, | ||
199 | ft_t_warn, "tape is not formatted"); | ||
200 | } | ||
201 | /* now enter defined state, read header segment if not | ||
202 | * already done and flush write buffers | ||
203 | */ | ||
204 | TRACE_CATCH(zft_def_idle_state(),); | ||
205 | zft_io_state = zft_reading; | ||
206 | if (zft_tape_at_eod(pos)) { | ||
207 | eod = 1; | ||
208 | TRACE_EXIT 1; | ||
209 | } | ||
210 | eod = 0; | ||
211 | *volume = zft_find_volume(pos->seg_pos); | ||
212 | /* get the space left until EOF */ | ||
213 | remaining = zft_check_for_eof(*volume, pos); | ||
214 | buf_len_rd = 0; | ||
215 | TRACE(ft_t_noise, "remaining: " LL_X ", vol_no: %d", | ||
216 | LL(remaining), (*volume)->count); | ||
217 | } else if (zft_tape_at_eod(pos)) { | ||
218 | if (++eod > 2) { | ||
219 | TRACE_EXIT -EIO; /* st.c also returns -EIO */ | ||
220 | } else { | ||
221 | TRACE_EXIT 1; | ||
222 | } | ||
223 | } | ||
224 | if ((*req_len % (*volume)->blk_sz) != 0) { | ||
225 | /* this message is informational only. The user gets the | ||
226 | * proper return value | ||
227 | */ | ||
228 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
229 | "req_len %d not a multiple of block size %d", | ||
230 | *req_len, (*volume)->blk_sz); | ||
231 | } | ||
232 | /* As GNU tar doesn't accept partial read counts when the | ||
233 | * multiple volume flag is set, we make sure to return the | ||
234 | * requested amount of data. Except, of course, at the end of | ||
235 | * the tape or file mark. | ||
236 | */ | ||
237 | remaining -= *req_len; | ||
238 | if (remaining <= 0) { | ||
239 | TRACE(ft_t_noise, | ||
240 | "clipped request from %d to %d.", | ||
241 | *req_len, (int)(*req_len + remaining)); | ||
242 | *req_len += remaining; | ||
243 | *req_clipped = 1; | ||
244 | } else { | ||
245 | *req_clipped = 0; | ||
246 | } | ||
247 | TRACE_EXIT 0; | ||
248 | } | ||
249 | |||
250 | /* this_segs_size: the current segment's size. | ||
251 | * buff: the USER-SPACE buffer provided by the calling function. | ||
252 | * req_len: how much data should be read at most. | ||
253 | * volume: contains information on current volume (blk_sz etc.) | ||
254 | */ | ||
255 | static int empty_deblock_buf(__u8 __user *usr_buf, const int req_len, | ||
256 | const __u8 *src_buf, const int seg_sz, | ||
257 | zft_position *pos, | ||
258 | const zft_volinfo *volume) | ||
259 | { | ||
260 | int cnt; | ||
261 | int result = 0; | ||
262 | TRACE_FUN(ft_t_flow); | ||
263 | |||
264 | TRACE(ft_t_data_flow, "this_segs_size: %d", seg_sz); | ||
265 | if (zft_use_compression && volume->use_compression) { | ||
266 | TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); | ||
267 | TRACE_CATCH(result= (*zft_cmpr_ops->read)(&cnt, | ||
268 | usr_buf, req_len, | ||
269 | src_buf, seg_sz, | ||
270 | pos, volume),); | ||
271 | } else { | ||
272 | TRACE_CATCH(result= zft_simple_read (&cnt, | ||
273 | usr_buf, req_len, | ||
274 | src_buf, seg_sz, | ||
275 | pos, volume),); | ||
276 | } | ||
277 | pos->volume_pos += result; | ||
278 | pos->tape_pos += cnt; | ||
279 | pos->seg_byte_pos += cnt; | ||
280 | buf_len_rd -= cnt; /* remaining bytes in buffer */ | ||
281 | TRACE(ft_t_data_flow, "buf_len_rd: %d, cnt: %d", buf_len_rd, cnt); | ||
282 | if(pos->seg_byte_pos >= seg_sz) { | ||
283 | pos->seg_pos++; | ||
284 | pos->seg_byte_pos = 0; | ||
285 | } | ||
286 | TRACE(ft_t_data_flow, "bytes moved out of deblock-buffer: %d", cnt); | ||
287 | TRACE_EXIT result; | ||
288 | } | ||
289 | |||
290 | |||
291 | /* note: we store the segment id of the segment that is inside the | ||
292 | * deblock buffer. This spares a lot of ftape_read_segment()s when we | ||
293 | * use small block-sizes. The block-size may be 1kb (SECTOR_SIZE). In | ||
294 | * this case a MTFSR 28 maybe still inside the same segment. | ||
295 | */ | ||
296 | int _zft_read(char __user *buff, int req_len) | ||
297 | { | ||
298 | int req_clipped; | ||
299 | int result = 0; | ||
300 | int bytes_read = 0; | ||
301 | static unsigned int seg_sz = 0; | ||
302 | static const zft_volinfo *volume = NULL; | ||
303 | TRACE_FUN(ft_t_flow); | ||
304 | |||
305 | zft_resid = req_len; | ||
306 | result = check_read_access(&req_len, &volume, | ||
307 | &req_clipped, &zft_pos); | ||
308 | switch(result) { | ||
309 | case 0: | ||
310 | break; /* nothing special */ | ||
311 | case 1: | ||
312 | TRACE(ft_t_noise, "EOD reached"); | ||
313 | TRACE_EXIT 0; /* EOD */ | ||
314 | default: | ||
315 | TRACE_ABORT(result, ft_t_noise, | ||
316 | "check_read_access() failed with result %d", | ||
317 | result); | ||
318 | TRACE_EXIT result; | ||
319 | } | ||
320 | while (req_len > 0) { | ||
321 | /* Allow escape from this loop on signal ! | ||
322 | */ | ||
323 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
324 | /* buf_len_rd == 0 means that we need to read a new | ||
325 | * segment. | ||
326 | */ | ||
327 | if (buf_len_rd == 0) { | ||
328 | while((result = zft_fetch_segment(zft_pos.seg_pos, | ||
329 | zft_deblock_buf, | ||
330 | FT_RD_AHEAD)) == 0) { | ||
331 | zft_pos.seg_pos ++; | ||
332 | zft_pos.seg_byte_pos = 0; | ||
333 | } | ||
334 | if (result < 0) { | ||
335 | zft_resid -= bytes_read; | ||
336 | TRACE_ABORT(result, ft_t_noise, | ||
337 | "zft_fetch_segment(): %d", | ||
338 | result); | ||
339 | } | ||
340 | seg_sz = result; | ||
341 | buf_len_rd = seg_sz - zft_pos.seg_byte_pos; | ||
342 | } | ||
343 | TRACE_CATCH(result = empty_deblock_buf(buff, | ||
344 | req_len, | ||
345 | zft_deblock_buf, | ||
346 | seg_sz, | ||
347 | &zft_pos, | ||
348 | volume), | ||
349 | zft_resid -= bytes_read); | ||
350 | TRACE(ft_t_data_flow, "bytes just read: %d", result); | ||
351 | bytes_read += result; /* what we got so far */ | ||
352 | buff += result; /* index in user-buffer */ | ||
353 | req_len -= result; /* what's left from req_len */ | ||
354 | } /* while (req_len > 0) */ | ||
355 | if (req_clipped) { | ||
356 | TRACE(ft_t_data_flow, | ||
357 | "maybe partial count because of eof mark"); | ||
358 | if (zft_just_before_eof && bytes_read == 0) { | ||
359 | /* req_len was > 0, but user didn't get | ||
360 | * anything the user has read in the eof-mark | ||
361 | */ | ||
362 | zft_move_past_eof(&zft_pos); | ||
363 | ftape_abort_operation(); | ||
364 | } else { | ||
365 | /* don't skip to the next file before the user | ||
366 | * tried to read a second time past EOF Just | ||
367 | * mark that we are at EOF and maybe decrement | ||
368 | * zft_seg_pos to stay in the same volume; | ||
369 | */ | ||
370 | zft_just_before_eof = 1; | ||
371 | zft_position_before_eof(&zft_pos, volume); | ||
372 | TRACE(ft_t_noise, "just before eof"); | ||
373 | } | ||
374 | } | ||
375 | zft_resid -= result; /* for MTSTATUS */ | ||
376 | TRACE_EXIT bytes_read; | ||
377 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-read.h b/drivers/char/ftape/zftape/zftape-read.h new file mode 100644 index 000000000000..42941de0c23a --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-read.h | |||
@@ -0,0 +1,53 @@ | |||
1 | #ifndef _ZFTAPE_READ_H | ||
2 | #define _ZFTAPE_READ_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus-Justus Heine | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-read.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:07 $ | ||
25 | * | ||
26 | * This file contains the definitions for the read functions | ||
27 | * for the zftape driver for Linux. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include "../lowlevel/ftape-read.h" | ||
32 | |||
33 | /* ftape-read.c defined global vars. | ||
34 | */ | ||
35 | extern int zft_just_before_eof; | ||
36 | |||
37 | /* ftape-read.c defined global functions. | ||
38 | */ | ||
39 | extern void zft_zap_read_buffers(void); | ||
40 | extern int zft_read_header_segments(void); | ||
41 | extern int zft_fetch_segment_fraction(const unsigned int segment, | ||
42 | void *buffer, | ||
43 | const ft_read_mode_t read_mode, | ||
44 | const unsigned int start, | ||
45 | const unsigned int size); | ||
46 | #define zft_fetch_segment(segment, address, read_mode) \ | ||
47 | zft_fetch_segment_fraction(segment, address, read_mode, \ | ||
48 | 0, FT_SEGMENT_SIZE) | ||
49 | /* hook for the VFS interface | ||
50 | */ | ||
51 | extern int _zft_read(char __user *buff, int req_len); | ||
52 | |||
53 | #endif /* _ZFTAPE_READ_H */ | ||
diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c new file mode 100644 index 000000000000..a61ef50f3dfc --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-rw.c | |||
@@ -0,0 +1,376 @@ | |||
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 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-rw.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:19:08 $ | ||
22 | * | ||
23 | * This file contains some common code for the r/w code for | ||
24 | * zftape. | ||
25 | */ | ||
26 | |||
27 | #include <linux/config.h> /* for CONFIG_ZFT_DFLT_BLK_SZ */ | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/mm.h> | ||
30 | |||
31 | #include <linux/zftape.h> | ||
32 | #include "../zftape/zftape-init.h" | ||
33 | #include "../zftape/zftape-eof.h" | ||
34 | #include "../zftape/zftape-ctl.h" | ||
35 | #include "../zftape/zftape-write.h" | ||
36 | #include "../zftape/zftape-read.h" | ||
37 | #include "../zftape/zftape-rw.h" | ||
38 | #include "../zftape/zftape-vtbl.h" | ||
39 | |||
40 | /* Global vars. | ||
41 | */ | ||
42 | |||
43 | __u8 *zft_deblock_buf; | ||
44 | __u8 *zft_hseg_buf; | ||
45 | int zft_deblock_segment = -1; | ||
46 | zft_status_enum zft_io_state = zft_idle; | ||
47 | int zft_header_changed; | ||
48 | int zft_qic113; /* conform to old specs. and old zftape */ | ||
49 | int zft_use_compression; | ||
50 | zft_position zft_pos = { | ||
51 | -1, /* seg_pos */ | ||
52 | 0, /* seg_byte_pos */ | ||
53 | 0, /* tape_pos */ | ||
54 | 0 /* volume_pos */ | ||
55 | }; | ||
56 | unsigned int zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; | ||
57 | __s64 zft_capacity; | ||
58 | |||
59 | unsigned int zft_written_segments; | ||
60 | int zft_label_changed; | ||
61 | |||
62 | /* Local vars. | ||
63 | */ | ||
64 | |||
65 | unsigned int zft_get_seg_sz(unsigned int segment) | ||
66 | { | ||
67 | int size; | ||
68 | TRACE_FUN(ft_t_any); | ||
69 | |||
70 | size = FT_SEGMENT_SIZE - | ||
71 | count_ones(ftape_get_bad_sector_entry(segment))*FT_SECTOR_SIZE; | ||
72 | if (size > 0) { | ||
73 | TRACE_EXIT (unsigned)size; | ||
74 | } else { | ||
75 | TRACE_EXIT 0; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | /* ftape_set_flags(). Claus-Justus Heine, 1994/1995 | ||
80 | */ | ||
81 | void zft_set_flags(unsigned minor_unit) | ||
82 | { | ||
83 | TRACE_FUN(ft_t_flow); | ||
84 | |||
85 | zft_use_compression = zft_qic_mode = 0; | ||
86 | switch (minor_unit & ZFT_MINOR_OP_MASK) { | ||
87 | case (ZFT_Q80_MODE | ZFT_ZIP_MODE): | ||
88 | case ZFT_ZIP_MODE: | ||
89 | zft_use_compression = 1; | ||
90 | case 0: | ||
91 | case ZFT_Q80_MODE: | ||
92 | zft_qic_mode = 1; | ||
93 | if (zft_mt_compression) { /* override the default */ | ||
94 | zft_use_compression = 1; | ||
95 | } | ||
96 | break; | ||
97 | case ZFT_RAW_MODE: | ||
98 | TRACE(ft_t_noise, "switching to raw mode"); | ||
99 | break; | ||
100 | default: | ||
101 | TRACE(ft_t_warn, "Warning:\n" | ||
102 | KERN_INFO "Wrong combination of minor device bits.\n" | ||
103 | KERN_INFO "Switching to raw read-only mode."); | ||
104 | zft_write_protected = 1; | ||
105 | break; | ||
106 | } | ||
107 | TRACE_EXIT; | ||
108 | } | ||
109 | |||
110 | /* computes the segment and byte offset inside the segment | ||
111 | * corresponding to tape_pos. | ||
112 | * | ||
113 | * tape_pos gives the offset in bytes from the beginning of the | ||
114 | * ft_first_data_segment *seg_byte_pos is the offset in the current | ||
115 | * segment in bytes | ||
116 | * | ||
117 | * Of, if this routine was called often one should cache the last data | ||
118 | * pos it was called with, but actually this is only needed in | ||
119 | * ftape_seek_block(), that is, almost never. | ||
120 | */ | ||
121 | int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos) | ||
122 | { | ||
123 | int segment; | ||
124 | int seg_sz; | ||
125 | TRACE_FUN(ft_t_flow); | ||
126 | |||
127 | if (tape_pos == 0) { | ||
128 | *seg_byte_pos = 0; | ||
129 | segment = ft_first_data_segment; | ||
130 | } else { | ||
131 | seg_sz = 0; | ||
132 | |||
133 | for (segment = ft_first_data_segment; | ||
134 | ((tape_pos > 0) && (segment <= ft_last_data_segment)); | ||
135 | segment++) { | ||
136 | seg_sz = zft_get_seg_sz(segment); | ||
137 | tape_pos -= seg_sz; | ||
138 | } | ||
139 | if(tape_pos >= 0) { | ||
140 | /* the case tape_pos > != 0 means that the | ||
141 | * argument tape_pos lies beyond the EOT. | ||
142 | */ | ||
143 | *seg_byte_pos= 0; | ||
144 | } else { /* tape_pos < 0 */ | ||
145 | segment--; | ||
146 | *seg_byte_pos= tape_pos + seg_sz; | ||
147 | } | ||
148 | } | ||
149 | TRACE_EXIT(segment); | ||
150 | } | ||
151 | |||
152 | /* ftape_calc_tape_pos(). | ||
153 | * | ||
154 | * computes the offset in bytes from the beginning of the | ||
155 | * ft_first_data_segment inverse to ftape_calc_seg_byte_coord | ||
156 | * | ||
157 | * We should do some caching. But how: | ||
158 | * | ||
159 | * Each time the header segments are read in, this routine is called | ||
160 | * with ft_tracks_per_tape*segments_per_track argumnet. So this should be | ||
161 | * the time to reset the cache. | ||
162 | * | ||
163 | * Also, it might be in the future that the bad sector map gets | ||
164 | * changed. -> reset the cache | ||
165 | */ | ||
166 | static int seg_pos; | ||
167 | static __s64 tape_pos; | ||
168 | |||
169 | __s64 zft_get_capacity(void) | ||
170 | { | ||
171 | seg_pos = ft_first_data_segment; | ||
172 | tape_pos = 0; | ||
173 | |||
174 | while (seg_pos <= ft_last_data_segment) { | ||
175 | tape_pos += zft_get_seg_sz(seg_pos ++); | ||
176 | } | ||
177 | return tape_pos; | ||
178 | } | ||
179 | |||
180 | __s64 zft_calc_tape_pos(int segment) | ||
181 | { | ||
182 | int d1, d2, d3; | ||
183 | TRACE_FUN(ft_t_any); | ||
184 | |||
185 | if (segment > ft_last_data_segment) { | ||
186 | TRACE_EXIT zft_capacity; | ||
187 | } | ||
188 | if (segment < ft_first_data_segment) { | ||
189 | TRACE_EXIT 0; | ||
190 | } | ||
191 | d2 = segment - seg_pos; | ||
192 | if (-d2 > 10) { | ||
193 | d1 = segment - ft_first_data_segment; | ||
194 | if (-d2 > d1) { | ||
195 | tape_pos = 0; | ||
196 | seg_pos = ft_first_data_segment; | ||
197 | d2 = d1; | ||
198 | } | ||
199 | } | ||
200 | if (d2 > 10) { | ||
201 | d3 = ft_last_data_segment - segment; | ||
202 | if (d2 > d3) { | ||
203 | tape_pos = zft_capacity; | ||
204 | seg_pos = ft_last_data_segment + 1; | ||
205 | d2 = -d3; | ||
206 | } | ||
207 | } | ||
208 | if (d2 > 0) { | ||
209 | while (seg_pos < segment) { | ||
210 | tape_pos += zft_get_seg_sz(seg_pos++); | ||
211 | } | ||
212 | } else { | ||
213 | while (seg_pos > segment) { | ||
214 | tape_pos -= zft_get_seg_sz(--seg_pos); | ||
215 | } | ||
216 | } | ||
217 | TRACE(ft_t_noise, "new cached pos: %d", seg_pos); | ||
218 | |||
219 | TRACE_EXIT tape_pos; | ||
220 | } | ||
221 | |||
222 | /* copy Z-label string to buffer, keeps track of the correct offset in | ||
223 | * `buffer' | ||
224 | */ | ||
225 | void zft_update_label(__u8 *buffer) | ||
226 | { | ||
227 | TRACE_FUN(ft_t_flow); | ||
228 | |||
229 | if (strncmp(&buffer[FT_LABEL], ZFTAPE_LABEL, | ||
230 | sizeof(ZFTAPE_LABEL)-1) != 0) { | ||
231 | TRACE(ft_t_info, "updating label from \"%s\" to \"%s\"", | ||
232 | &buffer[FT_LABEL], ZFTAPE_LABEL); | ||
233 | strcpy(&buffer[FT_LABEL], ZFTAPE_LABEL); | ||
234 | memset(&buffer[FT_LABEL] + sizeof(ZFTAPE_LABEL) - 1, ' ', | ||
235 | FT_LABEL_SZ - sizeof(ZFTAPE_LABEL + 1)); | ||
236 | PUT4(buffer, FT_LABEL_DATE, 0); | ||
237 | zft_label_changed = zft_header_changed = 1; /* changed */ | ||
238 | } | ||
239 | TRACE_EXIT; | ||
240 | } | ||
241 | |||
242 | int zft_verify_write_segments(unsigned int segment, | ||
243 | __u8 *data, size_t size, | ||
244 | __u8 *buffer) | ||
245 | { | ||
246 | int result; | ||
247 | __u8 *write_buf; | ||
248 | __u8 *src_buf; | ||
249 | int single; | ||
250 | int seg_pos; | ||
251 | int seg_sz; | ||
252 | int remaining; | ||
253 | ft_write_mode_t write_mode; | ||
254 | TRACE_FUN(ft_t_flow); | ||
255 | |||
256 | seg_pos = segment; | ||
257 | seg_sz = zft_get_seg_sz(seg_pos); | ||
258 | src_buf = data; | ||
259 | single = size <= seg_sz; | ||
260 | remaining = size; | ||
261 | do { | ||
262 | TRACE(ft_t_noise, "\n" | ||
263 | KERN_INFO "remaining: %d\n" | ||
264 | KERN_INFO "seg_sz : %d\n" | ||
265 | KERN_INFO "segment : %d", | ||
266 | remaining, seg_sz, seg_pos); | ||
267 | if (remaining == seg_sz) { | ||
268 | write_buf = src_buf; | ||
269 | write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI; | ||
270 | remaining = 0; | ||
271 | } else if (remaining > seg_sz) { | ||
272 | write_buf = src_buf; | ||
273 | write_mode = FT_WR_ASYNC; /* don't start tape */ | ||
274 | remaining -= seg_sz; | ||
275 | } else { /* remaining < seg_sz */ | ||
276 | write_buf = buffer; | ||
277 | memcpy(write_buf, src_buf, remaining); | ||
278 | memset(&write_buf[remaining],'\0',seg_sz-remaining); | ||
279 | write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI; | ||
280 | remaining = 0; | ||
281 | } | ||
282 | if ((result = ftape_write_segment(seg_pos, | ||
283 | write_buf, | ||
284 | write_mode)) != seg_sz) { | ||
285 | TRACE(ft_t_err, "Error: " | ||
286 | "Couldn't write segment %d", seg_pos); | ||
287 | TRACE_EXIT result < 0 ? result : -EIO; /* bail out */ | ||
288 | } | ||
289 | zft_written_segments ++; | ||
290 | seg_sz = zft_get_seg_sz(++seg_pos); | ||
291 | src_buf += result; | ||
292 | } while (remaining > 0); | ||
293 | if (ftape_get_status()->fti_state == writing) { | ||
294 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
295 | TRACE_CATCH(ftape_abort_operation(),); | ||
296 | zft_prevent_flush(); | ||
297 | } | ||
298 | seg_pos = segment; | ||
299 | src_buf = data; | ||
300 | remaining = size; | ||
301 | do { | ||
302 | TRACE_CATCH(result = ftape_read_segment(seg_pos, buffer, | ||
303 | single ? FT_RD_SINGLE | ||
304 | : FT_RD_AHEAD),); | ||
305 | if (memcmp(src_buf, buffer, | ||
306 | remaining > result ? result : remaining) != 0) { | ||
307 | TRACE_ABORT(-EIO, ft_t_err, | ||
308 | "Failed to verify written segment %d", | ||
309 | seg_pos); | ||
310 | } | ||
311 | remaining -= result; | ||
312 | TRACE(ft_t_noise, "verify successful:\n" | ||
313 | KERN_INFO "segment : %d\n" | ||
314 | KERN_INFO "segsize : %d\n" | ||
315 | KERN_INFO "remaining: %d", | ||
316 | seg_pos, result, remaining); | ||
317 | src_buf += seg_sz; | ||
318 | seg_pos++; | ||
319 | } while (remaining > 0); | ||
320 | TRACE_EXIT size; | ||
321 | } | ||
322 | |||
323 | |||
324 | /* zft_erase(). implemented compression-handling | ||
325 | * | ||
326 | * calculate the first data-segment when using/not using compression. | ||
327 | * | ||
328 | * update header-segment and compression-map-segment. | ||
329 | */ | ||
330 | int zft_erase(void) | ||
331 | { | ||
332 | int result = 0; | ||
333 | TRACE_FUN(ft_t_flow); | ||
334 | |||
335 | if (!zft_header_read) { | ||
336 | TRACE_CATCH(zft_vmalloc_once((void **)&zft_hseg_buf, | ||
337 | FT_SEGMENT_SIZE),); | ||
338 | /* no need to read the vtbl and compression map */ | ||
339 | TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),); | ||
340 | if ((zft_old_ftape = | ||
341 | zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]))) { | ||
342 | zft_ftape_extract_file_marks(zft_hseg_buf); | ||
343 | } | ||
344 | TRACE(ft_t_noise, | ||
345 | "ft_first_data_segment: %d, ft_last_data_segment: %d", | ||
346 | ft_first_data_segment, ft_last_data_segment); | ||
347 | zft_qic113 = (ft_format_code != fmt_normal && | ||
348 | ft_format_code != fmt_1100ft && | ||
349 | ft_format_code != fmt_425ft); | ||
350 | } | ||
351 | if (zft_old_ftape) { | ||
352 | zft_clear_ftape_file_marks(); | ||
353 | zft_old_ftape = 0; /* no longer old ftape */ | ||
354 | } | ||
355 | PUT2(zft_hseg_buf, FT_CMAP_START, 0); | ||
356 | zft_volume_table_changed = 1; | ||
357 | zft_capacity = zft_get_capacity(); | ||
358 | zft_init_vtbl(); | ||
359 | /* the rest must be done in ftape_update_header_segments | ||
360 | */ | ||
361 | zft_header_read = 1; | ||
362 | zft_header_changed = 1; /* force update of timestamp */ | ||
363 | result = zft_update_header_segments(); | ||
364 | |||
365 | ftape_abort_operation(); | ||
366 | |||
367 | zft_reset_position(&zft_pos); | ||
368 | zft_set_flags (zft_unit); | ||
369 | TRACE_EXIT result; | ||
370 | } | ||
371 | |||
372 | unsigned int zft_get_time(void) | ||
373 | { | ||
374 | unsigned int date = FT_TIME_STAMP(2097, 11, 30, 23, 59, 59); /* fun */ | ||
375 | return date; | ||
376 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-rw.h b/drivers/char/ftape/zftape/zftape-rw.h new file mode 100644 index 000000000000..14c07f086575 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-rw.h | |||
@@ -0,0 +1,102 @@ | |||
1 | #ifndef _ZFTAPE_RW_H | ||
2 | #define _ZFTAPE_RW_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus-Justus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-rw.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:09 $ | ||
25 | * | ||
26 | * This file contains the definitions for the read and write | ||
27 | * functions for the QIC-117 floppy-tape driver for Linux. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/config.h> /* for CONFIG_ZFT_DFLT_BLK_SZ */ | ||
32 | #include "../zftape/zftape-buffers.h" | ||
33 | |||
34 | #define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape) | ||
35 | |||
36 | /* QIC-113 Rev. G says that `a maximum of 63488 raw bytes may be | ||
37 | * compressed into a single frame'. | ||
38 | * Maybe we should stick to 32kb to make it more `beautiful' | ||
39 | */ | ||
40 | #define ZFT_MAX_BLK_SZ (62*1024) /* bytes */ | ||
41 | #if !defined(CONFIG_ZFT_DFLT_BLK_SZ) | ||
42 | # define CONFIG_ZFT_DFLT_BLK_SZ (10*1024) /* bytes, default of gnu tar */ | ||
43 | #elif CONFIG_ZFT_DFLT_BLK_SZ == 0 | ||
44 | # undef CONFIG_ZFT_DFLT_BLK_SZ | ||
45 | # define CONFIG_ZFT_DFLT_BLK_SZ 1 | ||
46 | #elif (CONFIG_ZFT_DFLT_BLK_SZ % 1024) != 0 | ||
47 | # error CONFIG_ZFT_DFLT_BLK_SZ must be 1 or a multiple of 1024 | ||
48 | #endif | ||
49 | /* The *optional* compression routines need some overhead per tape | ||
50 | * block for their purposes. Instead of asking the actual compression | ||
51 | * implementation how much it needs, we restrict this overhead to be | ||
52 | * maximal of ZFT_CMPT_OVERHEAD size. We need this for EOT | ||
53 | * conditions. The tape is assumed to be logical at EOT when the | ||
54 | * distance from the physical EOT is less than | ||
55 | * one tape block + ZFT_CMPR_OVERHEAD | ||
56 | */ | ||
57 | #define ZFT_CMPR_OVERHEAD 16 /* bytes */ | ||
58 | |||
59 | typedef enum | ||
60 | { | ||
61 | zft_idle = 0, | ||
62 | zft_reading, | ||
63 | zft_writing, | ||
64 | } zft_status_enum; | ||
65 | |||
66 | typedef struct /* all values measured in bytes */ | ||
67 | { | ||
68 | int seg_pos; /* segment currently positioned at */ | ||
69 | int seg_byte_pos; /* offset in current segment */ | ||
70 | __s64 tape_pos; /* real offset from BOT */ | ||
71 | __s64 volume_pos; /* pos. in uncompressed data stream in | ||
72 | * current volume | ||
73 | */ | ||
74 | } zft_position; | ||
75 | |||
76 | extern zft_position zft_pos; | ||
77 | extern __u8 *zft_deblock_buf; | ||
78 | extern __u8 *zft_hseg_buf; | ||
79 | extern int zft_deblock_segment; | ||
80 | extern zft_status_enum zft_io_state; | ||
81 | extern int zft_header_changed; | ||
82 | extern int zft_qic113; /* conform to old specs. and old zftape */ | ||
83 | extern int zft_use_compression; | ||
84 | extern unsigned int zft_blk_sz; | ||
85 | extern __s64 zft_capacity; | ||
86 | extern unsigned int zft_written_segments; | ||
87 | extern int zft_label_changed; | ||
88 | |||
89 | /* zftape-rw.c exported functions | ||
90 | */ | ||
91 | extern unsigned int zft_get_seg_sz(unsigned int segment); | ||
92 | extern void zft_set_flags(unsigned int minor_unit); | ||
93 | extern int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos); | ||
94 | extern __s64 zft_calc_tape_pos(int segment); | ||
95 | extern __s64 zft_get_capacity(void); | ||
96 | extern void zft_update_label(__u8 *buffer); | ||
97 | extern int zft_erase(void); | ||
98 | extern int zft_verify_write_segments(unsigned int segment, | ||
99 | __u8 *data, size_t size, __u8 *buffer); | ||
100 | extern unsigned int zft_get_time(void); | ||
101 | #endif /* _ZFTAPE_RW_H */ | ||
102 | |||
diff --git a/drivers/char/ftape/zftape/zftape-vtbl.c b/drivers/char/ftape/zftape/zftape-vtbl.c new file mode 100644 index 000000000000..ad7f8be6340b --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-vtbl.c | |||
@@ -0,0 +1,757 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1995-1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU General Public License as | ||
6 | published by the Free Software Foundation; either version 2, or (at | ||
7 | your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, but | ||
10 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | 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, | ||
17 | USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.c,v $ | ||
21 | * $Revision: 1.7.6.1 $ | ||
22 | * $Date: 1997/11/24 13:48:31 $ | ||
23 | * | ||
24 | * This file defines a volume table as defined in various QIC | ||
25 | * standards. | ||
26 | * | ||
27 | * This is a minimal implementation, just allowing ordinary DOS | ||
28 | * :( prgrams to identify the cartridge as used. | ||
29 | */ | ||
30 | |||
31 | #include <linux/errno.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/slab.h> | ||
34 | |||
35 | #include <linux/zftape.h> | ||
36 | #include "../zftape/zftape-init.h" | ||
37 | #include "../zftape/zftape-eof.h" | ||
38 | #include "../zftape/zftape-ctl.h" | ||
39 | #include "../zftape/zftape-write.h" | ||
40 | #include "../zftape/zftape-read.h" | ||
41 | #include "../zftape/zftape-rw.h" | ||
42 | #include "../zftape/zftape-vtbl.h" | ||
43 | |||
44 | #define ZFT_CMAP_HACK /* leave this defined to hide the compression map */ | ||
45 | |||
46 | /* | ||
47 | * global variables | ||
48 | */ | ||
49 | int zft_qic_mode = 1; /* use the vtbl */ | ||
50 | int zft_old_ftape; /* prevents old ftaped tapes to be overwritten */ | ||
51 | int zft_volume_table_changed; /* for write_header_segments() */ | ||
52 | |||
53 | /* | ||
54 | * private variables (only exported for inline functions) | ||
55 | */ | ||
56 | LIST_HEAD(zft_vtbl); | ||
57 | |||
58 | /* We could also allocate these dynamically when extracting the volume table | ||
59 | * sizeof(zft_volinfo) is about 32 or something close to that | ||
60 | */ | ||
61 | static zft_volinfo tape_vtbl; | ||
62 | static zft_volinfo eot_vtbl; | ||
63 | static zft_volinfo *cur_vtbl; | ||
64 | |||
65 | static inline void zft_new_vtbl_entry(void) | ||
66 | { | ||
67 | struct list_head *tmp = &zft_last_vtbl->node; | ||
68 | zft_volinfo *new = zft_kmalloc(sizeof(zft_volinfo)); | ||
69 | |||
70 | list_add(&new->node, tmp); | ||
71 | new->count = zft_eom_vtbl->count ++; | ||
72 | } | ||
73 | |||
74 | void zft_free_vtbl(void) | ||
75 | { | ||
76 | for (;;) { | ||
77 | struct list_head *tmp = zft_vtbl.prev; | ||
78 | zft_volinfo *vtbl; | ||
79 | |||
80 | if (tmp == &zft_vtbl) | ||
81 | break; | ||
82 | list_del(tmp); | ||
83 | vtbl = list_entry(tmp, zft_volinfo, node); | ||
84 | zft_kfree(vtbl, sizeof(zft_volinfo)); | ||
85 | } | ||
86 | INIT_LIST_HEAD(&zft_vtbl); | ||
87 | cur_vtbl = NULL; | ||
88 | } | ||
89 | |||
90 | /* initialize vtbl, called by ftape_new_cartridge() | ||
91 | */ | ||
92 | void zft_init_vtbl(void) | ||
93 | { | ||
94 | zft_volinfo *new; | ||
95 | |||
96 | zft_free_vtbl(); | ||
97 | |||
98 | /* Create the two dummy vtbl entries | ||
99 | */ | ||
100 | new = zft_kmalloc(sizeof(zft_volinfo)); | ||
101 | list_add(&new->node, &zft_vtbl); | ||
102 | new = zft_kmalloc(sizeof(zft_volinfo)); | ||
103 | list_add(&new->node, &zft_vtbl); | ||
104 | zft_head_vtbl->end_seg = ft_first_data_segment; | ||
105 | zft_head_vtbl->blk_sz = zft_blk_sz; | ||
106 | zft_head_vtbl->count = -1; | ||
107 | zft_eom_vtbl->start_seg = ft_first_data_segment + 1; | ||
108 | zft_eom_vtbl->end_seg = ft_last_data_segment + 1; | ||
109 | zft_eom_vtbl->blk_sz = zft_blk_sz; | ||
110 | zft_eom_vtbl->count = 0; | ||
111 | |||
112 | /* Reset the pointer for zft_find_volume() | ||
113 | */ | ||
114 | cur_vtbl = zft_eom_vtbl; | ||
115 | |||
116 | /* initialize the dummy vtbl entries for zft_qic_mode == 0 | ||
117 | */ | ||
118 | eot_vtbl.start_seg = ft_last_data_segment + 1; | ||
119 | eot_vtbl.end_seg = ft_last_data_segment + 1; | ||
120 | eot_vtbl.blk_sz = zft_blk_sz; | ||
121 | eot_vtbl.count = -1; | ||
122 | tape_vtbl.start_seg = ft_first_data_segment; | ||
123 | tape_vtbl.end_seg = ft_last_data_segment; | ||
124 | tape_vtbl.blk_sz = zft_blk_sz; | ||
125 | tape_vtbl.size = zft_capacity; | ||
126 | tape_vtbl.count = 0; | ||
127 | } | ||
128 | |||
129 | /* check for a valid VTBL signature. | ||
130 | */ | ||
131 | static int vtbl_signature_valid(__u8 signature[4]) | ||
132 | { | ||
133 | const char *vtbl_ids[] = VTBL_IDS; /* valid signatures */ | ||
134 | int j; | ||
135 | |||
136 | for (j = 0; | ||
137 | (j < NR_ITEMS(vtbl_ids)) && (memcmp(signature, vtbl_ids[j], 4) != 0); | ||
138 | j++); | ||
139 | return j < NR_ITEMS(vtbl_ids); | ||
140 | } | ||
141 | |||
142 | /* We used to store the block-size of the volume in the volume-label, | ||
143 | * using the keyword "blocksize". The blocksize written to the | ||
144 | * volume-label is in bytes. | ||
145 | * | ||
146 | * We use this now only for compatibility with old zftape version. We | ||
147 | * store the blocksize directly as binary number in the vendor | ||
148 | * extension part of the volume entry. | ||
149 | */ | ||
150 | static int check_volume_label(const char *label, int *blk_sz) | ||
151 | { | ||
152 | int valid_format; | ||
153 | char *blocksize; | ||
154 | TRACE_FUN(ft_t_flow); | ||
155 | |||
156 | TRACE(ft_t_noise, "called with \"%s\" / \"%s\"", label, ZFT_VOL_NAME); | ||
157 | if (strncmp(label, ZFT_VOL_NAME, strlen(ZFT_VOL_NAME)) != 0) { | ||
158 | *blk_sz = 1; /* smallest block size that we allow */ | ||
159 | valid_format = 0; | ||
160 | } else { | ||
161 | TRACE(ft_t_noise, "got old style zftape vtbl entry"); | ||
162 | /* get the default blocksize */ | ||
163 | /* use the kernel strstr() */ | ||
164 | blocksize= strstr(label, " blocksize "); | ||
165 | if (blocksize) { | ||
166 | blocksize += strlen(" blocksize "); | ||
167 | for(*blk_sz= 0; | ||
168 | *blocksize >= '0' && *blocksize <= '9'; | ||
169 | blocksize++) { | ||
170 | *blk_sz *= 10; | ||
171 | *blk_sz += *blocksize - '0'; | ||
172 | } | ||
173 | if (*blk_sz > ZFT_MAX_BLK_SZ) { | ||
174 | *blk_sz= 1; | ||
175 | valid_format= 0; | ||
176 | } else { | ||
177 | valid_format = 1; | ||
178 | } | ||
179 | } else { | ||
180 | *blk_sz= 1; | ||
181 | valid_format= 0; | ||
182 | } | ||
183 | } | ||
184 | TRACE_EXIT valid_format; | ||
185 | } | ||
186 | |||
187 | /* check for a zftape volume | ||
188 | */ | ||
189 | static int check_volume(__u8 *entry, zft_volinfo *volume) | ||
190 | { | ||
191 | TRACE_FUN(ft_t_flow); | ||
192 | |||
193 | if(strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, | ||
194 | strlen(ZFTAPE_SIG)) == 0) { | ||
195 | TRACE(ft_t_noise, "got new style zftape vtbl entry"); | ||
196 | volume->blk_sz = GET2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ); | ||
197 | volume->qic113 = entry[VTBL_EXT+EXT_ZFTAPE_QIC113]; | ||
198 | TRACE_EXIT 1; | ||
199 | } else { | ||
200 | TRACE_EXIT check_volume_label(&entry[VTBL_DESC], &volume->blk_sz); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | |||
205 | /* create zftape specific vtbl entry, the volume bounds are inserted | ||
206 | * in the calling function, zft_create_volume_headers() | ||
207 | */ | ||
208 | static void create_zft_volume(__u8 *entry, zft_volinfo *vtbl) | ||
209 | { | ||
210 | TRACE_FUN(ft_t_flow); | ||
211 | |||
212 | memset(entry, 0, VTBL_SIZE); | ||
213 | memcpy(&entry[VTBL_SIG], VTBL_ID, 4); | ||
214 | sprintf(&entry[VTBL_DESC], ZFT_VOL_NAME" %03d", vtbl->count); | ||
215 | entry[VTBL_FLAGS] = (VTBL_FL_NOT_VERIFIED | VTBL_FL_SEG_SPANNING); | ||
216 | entry[VTBL_M_NO] = 1; /* multi_cartridge_count */ | ||
217 | strcpy(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG); | ||
218 | PUT2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ, vtbl->blk_sz); | ||
219 | if (zft_qic113) { | ||
220 | PUT8(entry, VTBL_DATA_SIZE, vtbl->size); | ||
221 | entry[VTBL_CMPR] = VTBL_CMPR_UNREG; | ||
222 | if (vtbl->use_compression) { /* use compression: */ | ||
223 | entry[VTBL_CMPR] |= VTBL_CMPR_USED; | ||
224 | } | ||
225 | entry[VTBL_EXT+EXT_ZFTAPE_QIC113] = 1; | ||
226 | } else { | ||
227 | PUT4(entry, VTBL_DATA_SIZE, vtbl->size); | ||
228 | entry[VTBL_K_CMPR] = VTBL_CMPR_UNREG; | ||
229 | if (vtbl->use_compression) { /* use compression: */ | ||
230 | entry[VTBL_K_CMPR] |= VTBL_CMPR_USED; | ||
231 | } | ||
232 | } | ||
233 | if (ft_format_code == fmt_big) { | ||
234 | /* SCSI like vtbl, store the number of used | ||
235 | * segments as 4 byte value | ||
236 | */ | ||
237 | PUT4(entry, VTBL_SCSI_SEGS, vtbl->end_seg-vtbl->start_seg + 1); | ||
238 | } else { | ||
239 | /* normal, QIC-80MC like vtbl | ||
240 | */ | ||
241 | PUT2(entry, VTBL_START, vtbl->start_seg); | ||
242 | PUT2(entry, VTBL_END, vtbl->end_seg); | ||
243 | } | ||
244 | TRACE_EXIT; | ||
245 | } | ||
246 | |||
247 | /* this one creates the volume headers for each volume. It is assumed | ||
248 | * that buffer already contains the old volume-table, so that vtbl | ||
249 | * entries without the zft_volume flag set can savely be ignored. | ||
250 | */ | ||
251 | static void zft_create_volume_headers(__u8 *buffer) | ||
252 | { | ||
253 | __u8 *entry; | ||
254 | struct list_head *tmp; | ||
255 | zft_volinfo *vtbl; | ||
256 | TRACE_FUN(ft_t_flow); | ||
257 | |||
258 | #ifdef ZFT_CMAP_HACK | ||
259 | if((strncmp(&buffer[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, | ||
260 | strlen(ZFTAPE_SIG)) == 0) && | ||
261 | buffer[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { | ||
262 | TRACE(ft_t_noise, "deleting cmap volume"); | ||
263 | memmove(buffer, buffer + VTBL_SIZE, | ||
264 | FT_SEGMENT_SIZE - VTBL_SIZE); | ||
265 | } | ||
266 | #endif | ||
267 | entry = buffer; | ||
268 | for (tmp = zft_head_vtbl->node.next; | ||
269 | tmp != &zft_eom_vtbl->node; | ||
270 | tmp = tmp->next) { | ||
271 | vtbl = list_entry(tmp, zft_volinfo, node); | ||
272 | /* we now fill in the values only for newly created volumes. | ||
273 | */ | ||
274 | if (vtbl->new_volume) { | ||
275 | create_zft_volume(entry, vtbl); | ||
276 | vtbl->new_volume = 0; /* clear the flag */ | ||
277 | } | ||
278 | |||
279 | DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], vtbl); | ||
280 | entry += VTBL_SIZE; | ||
281 | } | ||
282 | memset(entry, 0, FT_SEGMENT_SIZE - zft_eom_vtbl->count * VTBL_SIZE); | ||
283 | TRACE_EXIT; | ||
284 | } | ||
285 | |||
286 | /* write volume table to tape. Calls zft_create_volume_headers() | ||
287 | */ | ||
288 | int zft_update_volume_table(unsigned int segment) | ||
289 | { | ||
290 | int result = 0; | ||
291 | __u8 *verify_buf = NULL; | ||
292 | TRACE_FUN(ft_t_flow); | ||
293 | |||
294 | TRACE_CATCH(result = ftape_read_segment(ft_first_data_segment, | ||
295 | zft_deblock_buf, | ||
296 | FT_RD_SINGLE),); | ||
297 | zft_create_volume_headers(zft_deblock_buf); | ||
298 | TRACE(ft_t_noise, "writing volume table segment %d", segment); | ||
299 | if (zft_vmalloc_once(&verify_buf, FT_SEGMENT_SIZE) == 0) { | ||
300 | TRACE_CATCH(zft_verify_write_segments(segment, | ||
301 | zft_deblock_buf, result, | ||
302 | verify_buf), | ||
303 | zft_vfree(&verify_buf, FT_SEGMENT_SIZE)); | ||
304 | zft_vfree(&verify_buf, FT_SEGMENT_SIZE); | ||
305 | } else { | ||
306 | TRACE_CATCH(ftape_write_segment(segment, zft_deblock_buf, | ||
307 | FT_WR_SINGLE),); | ||
308 | } | ||
309 | TRACE_EXIT 0; | ||
310 | } | ||
311 | |||
312 | /* non zftape volumes are handled in raw mode. Thus we need to | ||
313 | * calculate the raw amount of data contained in those segments. | ||
314 | */ | ||
315 | static void extract_alien_volume(__u8 *entry, zft_volinfo *vtbl) | ||
316 | { | ||
317 | TRACE_FUN(ft_t_flow); | ||
318 | |||
319 | vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) - | ||
320 | zft_calc_tape_pos(zft_last_vtbl->start_seg)); | ||
321 | vtbl->use_compression = 0; | ||
322 | vtbl->qic113 = zft_qic113; | ||
323 | if (vtbl->qic113) { | ||
324 | TRACE(ft_t_noise, | ||
325 | "Fake alien volume's size from " LL_X " to " LL_X, | ||
326 | LL(GET8(entry, VTBL_DATA_SIZE)), LL(vtbl->size)); | ||
327 | } else { | ||
328 | TRACE(ft_t_noise, | ||
329 | "Fake alien volume's size from %d to " LL_X, | ||
330 | (int)GET4(entry, VTBL_DATA_SIZE), LL(vtbl->size)); | ||
331 | } | ||
332 | TRACE_EXIT; | ||
333 | } | ||
334 | |||
335 | |||
336 | /* extract an zftape specific volume | ||
337 | */ | ||
338 | static void extract_zft_volume(__u8 *entry, zft_volinfo *vtbl) | ||
339 | { | ||
340 | TRACE_FUN(ft_t_flow); | ||
341 | |||
342 | if (vtbl->qic113) { | ||
343 | vtbl->size = GET8(entry, VTBL_DATA_SIZE); | ||
344 | vtbl->use_compression = | ||
345 | (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; | ||
346 | } else { | ||
347 | vtbl->size = GET4(entry, VTBL_DATA_SIZE); | ||
348 | if (entry[VTBL_K_CMPR] & VTBL_CMPR_UNREG) { | ||
349 | vtbl->use_compression = | ||
350 | (entry[VTBL_K_CMPR] & VTBL_CMPR_USED) != 0; | ||
351 | } else if (entry[VTBL_CMPR] & VTBL_CMPR_UNREG) { | ||
352 | vtbl->use_compression = | ||
353 | (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; | ||
354 | } else { | ||
355 | TRACE(ft_t_warn, "Geeh! There is something wrong:\n" | ||
356 | KERN_INFO "QIC compression (Rev = K): %x\n" | ||
357 | KERN_INFO "QIC compression (Rev > K): %x", | ||
358 | entry[VTBL_K_CMPR], entry[VTBL_CMPR]); | ||
359 | } | ||
360 | } | ||
361 | TRACE_EXIT; | ||
362 | } | ||
363 | |||
364 | /* extract the volume table from buffer. "buffer" must already contain | ||
365 | * the vtbl-segment | ||
366 | */ | ||
367 | int zft_extract_volume_headers(__u8 *buffer) | ||
368 | { | ||
369 | __u8 *entry; | ||
370 | TRACE_FUN(ft_t_flow); | ||
371 | |||
372 | zft_init_vtbl(); | ||
373 | entry = buffer; | ||
374 | #ifdef ZFT_CMAP_HACK | ||
375 | if ((strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, | ||
376 | strlen(ZFTAPE_SIG)) == 0) && | ||
377 | entry[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { | ||
378 | TRACE(ft_t_noise, "ignoring cmap volume"); | ||
379 | entry += VTBL_SIZE; | ||
380 | } | ||
381 | #endif | ||
382 | /* the end of the vtbl is indicated by an invalid signature | ||
383 | */ | ||
384 | while (vtbl_signature_valid(&entry[VTBL_SIG]) && | ||
385 | (entry - buffer) < FT_SEGMENT_SIZE) { | ||
386 | zft_new_vtbl_entry(); | ||
387 | if (ft_format_code == fmt_big) { | ||
388 | /* SCSI like vtbl, stores only the number of | ||
389 | * segments used | ||
390 | */ | ||
391 | unsigned int num_segments= GET4(entry, VTBL_SCSI_SEGS); | ||
392 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
393 | zft_last_vtbl->end_seg = | ||
394 | zft_last_vtbl->start_seg + num_segments - 1; | ||
395 | } else { | ||
396 | /* `normal', QIC-80 like vtbl | ||
397 | */ | ||
398 | zft_last_vtbl->start_seg = GET2(entry, VTBL_START); | ||
399 | zft_last_vtbl->end_seg = GET2(entry, VTBL_END); | ||
400 | } | ||
401 | zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1; | ||
402 | /* check if we created this volume and get the | ||
403 | * blk_sz | ||
404 | */ | ||
405 | zft_last_vtbl->zft_volume = check_volume(entry, zft_last_vtbl); | ||
406 | if (zft_last_vtbl->zft_volume == 0) { | ||
407 | extract_alien_volume(entry, zft_last_vtbl); | ||
408 | } else { | ||
409 | extract_zft_volume(entry, zft_last_vtbl); | ||
410 | } | ||
411 | DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], zft_last_vtbl); | ||
412 | entry +=VTBL_SIZE; | ||
413 | } | ||
414 | #if 0 | ||
415 | /* | ||
416 | * undefine to test end of tape handling | ||
417 | */ | ||
418 | zft_new_vtbl_entry(); | ||
419 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
420 | zft_last_vtbl->end_seg = ft_last_data_segment - 10; | ||
421 | zft_last_vtbl->blk_sz = zft_blk_sz; | ||
422 | zft_last_vtbl->zft_volume = 1; | ||
423 | zft_last_vtbl->qic113 = zft_qic113; | ||
424 | zft_last_vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) | ||
425 | - zft_calc_tape_pos(zft_last_vtbl->start_seg)); | ||
426 | #endif | ||
427 | TRACE_EXIT 0; | ||
428 | } | ||
429 | |||
430 | /* this functions translates the failed_sector_log, misused as | ||
431 | * EOF-marker list, into a virtual volume table. The table mustn't be | ||
432 | * written to tape, because this would occupy the first data segment, | ||
433 | * which should be the volume table, but is actually the first segment | ||
434 | * that is filled with data (when using standard ftape). We assume, | ||
435 | * that we get a non-empty failed_sector_log. | ||
436 | */ | ||
437 | int zft_fake_volume_headers (eof_mark_union *eof_map, int num_failed_sectors) | ||
438 | { | ||
439 | unsigned int segment, sector; | ||
440 | int have_eom = 0; | ||
441 | int vol_no; | ||
442 | TRACE_FUN(ft_t_flow); | ||
443 | |||
444 | if ((num_failed_sectors >= 2) && | ||
445 | (GET2(&eof_map[num_failed_sectors - 1].mark.segment, 0) | ||
446 | == | ||
447 | GET2(&eof_map[num_failed_sectors - 2].mark.segment, 0) + 1) && | ||
448 | (GET2(&eof_map[num_failed_sectors - 1].mark.date, 0) == 1)) { | ||
449 | /* this should be eom. We keep the remainder of the | ||
450 | * tape as another volume. | ||
451 | */ | ||
452 | have_eom = 1; | ||
453 | } | ||
454 | zft_init_vtbl(); | ||
455 | zft_eom_vtbl->start_seg = ft_first_data_segment; | ||
456 | for(vol_no = 0; vol_no < num_failed_sectors - have_eom; vol_no ++) { | ||
457 | zft_new_vtbl_entry(); | ||
458 | |||
459 | segment = GET2(&eof_map[vol_no].mark.segment, 0); | ||
460 | sector = GET2(&eof_map[vol_no].mark.date, 0); | ||
461 | |||
462 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
463 | zft_last_vtbl->end_seg = segment; | ||
464 | zft_eom_vtbl->start_seg = segment + 1; | ||
465 | zft_last_vtbl->blk_sz = 1; | ||
466 | zft_last_vtbl->size = | ||
467 | (zft_calc_tape_pos(zft_last_vtbl->end_seg) | ||
468 | - zft_calc_tape_pos(zft_last_vtbl->start_seg) | ||
469 | + (sector-1) * FT_SECTOR_SIZE); | ||
470 | TRACE(ft_t_noise, | ||
471 | "failed sector log: segment: %d, sector: %d", | ||
472 | segment, sector); | ||
473 | DUMP_VOLINFO(ft_t_noise, "Faked volume", zft_last_vtbl); | ||
474 | } | ||
475 | if (!have_eom) { | ||
476 | zft_new_vtbl_entry(); | ||
477 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
478 | zft_last_vtbl->end_seg = ft_last_data_segment; | ||
479 | zft_eom_vtbl->start_seg = ft_last_data_segment + 1; | ||
480 | zft_last_vtbl->size = zft_capacity; | ||
481 | zft_last_vtbl->size -= zft_calc_tape_pos(zft_last_vtbl->start_seg); | ||
482 | zft_last_vtbl->blk_sz = 1; | ||
483 | DUMP_VOLINFO(ft_t_noise, "Faked volume",zft_last_vtbl); | ||
484 | } | ||
485 | TRACE_EXIT 0; | ||
486 | } | ||
487 | |||
488 | /* update the internal volume table | ||
489 | * | ||
490 | * if before start of last volume: erase all following volumes if | ||
491 | * inside a volume: set end of volume to infinity | ||
492 | * | ||
493 | * this function is intended to be called every time _ftape_write() is | ||
494 | * called | ||
495 | * | ||
496 | * return: 0 if no new volume was created, 1 if a new volume was | ||
497 | * created | ||
498 | * | ||
499 | * NOTE: we don't need to check for zft_mode as ftape_write() does | ||
500 | * that already. This function gets never called without accessing | ||
501 | * zftape via the *qft* devices | ||
502 | */ | ||
503 | |||
504 | int zft_open_volume(zft_position *pos, int blk_sz, int use_compression) | ||
505 | { | ||
506 | TRACE_FUN(ft_t_flow); | ||
507 | |||
508 | if (!zft_qic_mode) { | ||
509 | TRACE_EXIT 0; | ||
510 | } | ||
511 | if (zft_tape_at_lbot(pos)) { | ||
512 | zft_init_vtbl(); | ||
513 | if(zft_old_ftape) { | ||
514 | /* clear old ftape's eof marks */ | ||
515 | zft_clear_ftape_file_marks(); | ||
516 | zft_old_ftape = 0; /* no longer old ftape */ | ||
517 | } | ||
518 | zft_reset_position(pos); | ||
519 | } | ||
520 | if (pos->seg_pos != zft_last_vtbl->end_seg + 1) { | ||
521 | TRACE_ABORT(-EIO, ft_t_bug, | ||
522 | "BUG: seg_pos: %d, zft_last_vtbl->end_seg: %d", | ||
523 | pos->seg_pos, zft_last_vtbl->end_seg); | ||
524 | } | ||
525 | TRACE(ft_t_noise, "create new volume"); | ||
526 | if (zft_eom_vtbl->count >= ZFT_MAX_VOLUMES) { | ||
527 | TRACE_ABORT(-ENOSPC, ft_t_err, | ||
528 | "Error: maxmimal number of volumes exhausted " | ||
529 | "(maxmimum is %d)", ZFT_MAX_VOLUMES); | ||
530 | } | ||
531 | zft_new_vtbl_entry(); | ||
532 | pos->volume_pos = pos->seg_byte_pos = 0; | ||
533 | zft_last_vtbl->start_seg = pos->seg_pos; | ||
534 | zft_last_vtbl->end_seg = ft_last_data_segment; /* infinity */ | ||
535 | zft_last_vtbl->blk_sz = blk_sz; | ||
536 | zft_last_vtbl->size = zft_capacity; | ||
537 | zft_last_vtbl->zft_volume = 1; | ||
538 | zft_last_vtbl->use_compression = use_compression; | ||
539 | zft_last_vtbl->qic113 = zft_qic113; | ||
540 | zft_last_vtbl->new_volume = 1; | ||
541 | zft_last_vtbl->open = 1; | ||
542 | zft_volume_table_changed = 1; | ||
543 | zft_eom_vtbl->start_seg = ft_last_data_segment + 1; | ||
544 | TRACE_EXIT 0; | ||
545 | } | ||
546 | |||
547 | /* perform mtfsf, mtbsf, not allowed without zft_qic_mode | ||
548 | */ | ||
549 | int zft_skip_volumes(int count, zft_position *pos) | ||
550 | { | ||
551 | const zft_volinfo *vtbl; | ||
552 | TRACE_FUN(ft_t_flow); | ||
553 | |||
554 | TRACE(ft_t_noise, "count: %d", count); | ||
555 | |||
556 | vtbl= zft_find_volume(pos->seg_pos); | ||
557 | while (count > 0 && vtbl != zft_eom_vtbl) { | ||
558 | vtbl = list_entry(vtbl->node.next, zft_volinfo, node); | ||
559 | count --; | ||
560 | } | ||
561 | while (count < 0 && vtbl != zft_first_vtbl) { | ||
562 | vtbl = list_entry(vtbl->node.prev, zft_volinfo, node); | ||
563 | count ++; | ||
564 | } | ||
565 | pos->seg_pos = vtbl->start_seg; | ||
566 | pos->seg_byte_pos = 0; | ||
567 | pos->volume_pos = 0; | ||
568 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
569 | zft_just_before_eof = vtbl->size == 0; | ||
570 | if (zft_cmpr_ops) { | ||
571 | (*zft_cmpr_ops->reset)(); | ||
572 | } | ||
573 | zft_deblock_segment = -1; /* no need to keep cache */ | ||
574 | TRACE(ft_t_noise, "repositioning to:\n" | ||
575 | KERN_INFO "zft_seg_pos : %d\n" | ||
576 | KERN_INFO "zft_seg_byte_pos : %d\n" | ||
577 | KERN_INFO "zft_tape_pos : " LL_X "\n" | ||
578 | KERN_INFO "zft_volume_pos : " LL_X "\n" | ||
579 | KERN_INFO "file number : %d", | ||
580 | pos->seg_pos, pos->seg_byte_pos, | ||
581 | LL(pos->tape_pos), LL(pos->volume_pos), vtbl->count); | ||
582 | zft_resid = count < 0 ? -count : count; | ||
583 | TRACE_EXIT zft_resid ? -EINVAL : 0; | ||
584 | } | ||
585 | |||
586 | /* the following simply returns the raw data position of the EOM | ||
587 | * marker, MTIOCSIZE ioctl | ||
588 | */ | ||
589 | __s64 zft_get_eom_pos(void) | ||
590 | { | ||
591 | if (zft_qic_mode) { | ||
592 | return zft_calc_tape_pos(zft_eom_vtbl->start_seg); | ||
593 | } else { | ||
594 | /* there is only one volume in raw mode */ | ||
595 | return zft_capacity; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | /* skip to eom, used for MTEOM | ||
600 | */ | ||
601 | void zft_skip_to_eom(zft_position *pos) | ||
602 | { | ||
603 | TRACE_FUN(ft_t_flow); | ||
604 | pos->seg_pos = zft_eom_vtbl->start_seg; | ||
605 | pos->seg_byte_pos = | ||
606 | pos->volume_pos = | ||
607 | zft_just_before_eof = 0; | ||
608 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
609 | TRACE(ft_t_noise, "ftape positioned to segment %d, data pos " LL_X, | ||
610 | pos->seg_pos, LL(pos->tape_pos)); | ||
611 | TRACE_EXIT; | ||
612 | } | ||
613 | |||
614 | /* write an EOF-marker by setting zft_last_vtbl->end_seg to seg_pos. | ||
615 | * NOTE: this function assumes that zft_last_vtbl points to a valid | ||
616 | * vtbl entry | ||
617 | * | ||
618 | * NOTE: this routine always positions before the EOF marker | ||
619 | */ | ||
620 | int zft_close_volume(zft_position *pos) | ||
621 | { | ||
622 | TRACE_FUN(ft_t_any); | ||
623 | |||
624 | if (zft_vtbl_empty || !zft_last_vtbl->open) { /* should not happen */ | ||
625 | TRACE(ft_t_noise, "There are no volumes to finish"); | ||
626 | TRACE_EXIT -EIO; | ||
627 | } | ||
628 | if (pos->seg_byte_pos == 0 && | ||
629 | pos->seg_pos != zft_last_vtbl->start_seg) { | ||
630 | pos->seg_pos --; | ||
631 | pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos); | ||
632 | } | ||
633 | zft_last_vtbl->end_seg = pos->seg_pos; | ||
634 | zft_last_vtbl->size = pos->volume_pos; | ||
635 | zft_volume_table_changed = 1; | ||
636 | zft_just_before_eof = 1; | ||
637 | zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1; | ||
638 | zft_last_vtbl->open = 0; /* closed */ | ||
639 | TRACE_EXIT 0; | ||
640 | } | ||
641 | |||
642 | /* write count file-marks at current position. | ||
643 | * | ||
644 | * The tape is positioned after the eof-marker, that is at byte 0 of | ||
645 | * the segment following the eof-marker | ||
646 | * | ||
647 | * this function is only allowed in zft_qic_mode | ||
648 | * | ||
649 | * Only allowed when tape is at BOT or EOD. | ||
650 | */ | ||
651 | int zft_weof(unsigned int count, zft_position *pos) | ||
652 | { | ||
653 | |||
654 | TRACE_FUN(ft_t_flow); | ||
655 | |||
656 | if (!count) { /* write zero EOF marks should be a real no-op */ | ||
657 | TRACE_EXIT 0; | ||
658 | } | ||
659 | zft_volume_table_changed = 1; | ||
660 | if (zft_tape_at_lbot(pos)) { | ||
661 | zft_init_vtbl(); | ||
662 | if(zft_old_ftape) { | ||
663 | /* clear old ftape's eof marks */ | ||
664 | zft_clear_ftape_file_marks(); | ||
665 | zft_old_ftape = 0; /* no longer old ftape */ | ||
666 | } | ||
667 | } | ||
668 | if (zft_last_vtbl->open) { | ||
669 | zft_close_volume(pos); | ||
670 | zft_move_past_eof(pos); | ||
671 | count --; | ||
672 | } | ||
673 | /* now it's easy, just append eof-marks, that is empty | ||
674 | * volumes, to the end of the already recorded media. | ||
675 | */ | ||
676 | while (count > 0 && | ||
677 | pos->seg_pos <= ft_last_data_segment && | ||
678 | zft_eom_vtbl->count < ZFT_MAX_VOLUMES) { | ||
679 | TRACE(ft_t_noise, | ||
680 | "Writing zero sized file at segment %d", pos->seg_pos); | ||
681 | zft_new_vtbl_entry(); | ||
682 | zft_last_vtbl->start_seg = pos->seg_pos; | ||
683 | zft_last_vtbl->end_seg = pos->seg_pos; | ||
684 | zft_last_vtbl->size = 0; | ||
685 | zft_last_vtbl->blk_sz = zft_blk_sz; | ||
686 | zft_last_vtbl->zft_volume = 1; | ||
687 | zft_last_vtbl->use_compression = 0; | ||
688 | pos->tape_pos += zft_get_seg_sz(pos->seg_pos); | ||
689 | zft_eom_vtbl->start_seg = ++ pos->seg_pos; | ||
690 | count --; | ||
691 | } | ||
692 | if (count > 0) { | ||
693 | /* there are two possibilities: end of tape, or the | ||
694 | * maximum number of files is exhausted. | ||
695 | */ | ||
696 | zft_resid = count; | ||
697 | TRACE(ft_t_noise,"Number of marks NOT written: %d", zft_resid); | ||
698 | if (zft_eom_vtbl->count == ZFT_MAX_VOLUMES) { | ||
699 | TRACE_ABORT(-EINVAL, ft_t_warn, | ||
700 | "maximum allowed number of files " | ||
701 | "exhausted: %d", ZFT_MAX_VOLUMES); | ||
702 | } else { | ||
703 | TRACE_ABORT(-ENOSPC, | ||
704 | ft_t_noise, "reached end of tape"); | ||
705 | } | ||
706 | } | ||
707 | TRACE_EXIT 0; | ||
708 | } | ||
709 | |||
710 | const zft_volinfo *zft_find_volume(unsigned int seg_pos) | ||
711 | { | ||
712 | TRACE_FUN(ft_t_flow); | ||
713 | |||
714 | TRACE(ft_t_any, "called with seg_pos %d",seg_pos); | ||
715 | if (!zft_qic_mode) { | ||
716 | if (seg_pos > ft_last_data_segment) { | ||
717 | TRACE_EXIT &eot_vtbl; | ||
718 | } | ||
719 | tape_vtbl.blk_sz = zft_blk_sz; | ||
720 | TRACE_EXIT &tape_vtbl; | ||
721 | } | ||
722 | if (seg_pos < zft_first_vtbl->start_seg) { | ||
723 | TRACE_EXIT (cur_vtbl = zft_first_vtbl); | ||
724 | } | ||
725 | while (seg_pos > cur_vtbl->end_seg) { | ||
726 | cur_vtbl = list_entry(cur_vtbl->node.next, zft_volinfo, node); | ||
727 | TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg); | ||
728 | } | ||
729 | while (seg_pos < cur_vtbl->start_seg) { | ||
730 | cur_vtbl = list_entry(cur_vtbl->node.prev, zft_volinfo, node); | ||
731 | TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg); | ||
732 | } | ||
733 | if (seg_pos > cur_vtbl->end_seg || seg_pos < cur_vtbl->start_seg) { | ||
734 | TRACE(ft_t_bug, "This cannot happen"); | ||
735 | } | ||
736 | DUMP_VOLINFO(ft_t_noise, "", cur_vtbl); | ||
737 | TRACE_EXIT cur_vtbl; | ||
738 | } | ||
739 | |||
740 | /* this function really assumes that we are just before eof | ||
741 | */ | ||
742 | void zft_move_past_eof(zft_position *pos) | ||
743 | { | ||
744 | TRACE_FUN(ft_t_flow); | ||
745 | |||
746 | TRACE(ft_t_noise, "old seg. pos: %d", pos->seg_pos); | ||
747 | pos->tape_pos += zft_get_seg_sz(pos->seg_pos++) - pos->seg_byte_pos; | ||
748 | pos->seg_byte_pos = 0; | ||
749 | pos->volume_pos = 0; | ||
750 | if (zft_cmpr_ops) { | ||
751 | (*zft_cmpr_ops->reset)(); | ||
752 | } | ||
753 | zft_just_before_eof = 0; | ||
754 | zft_deblock_segment = -1; /* no need to cache it anymore */ | ||
755 | TRACE(ft_t_noise, "new seg. pos: %d", pos->seg_pos); | ||
756 | TRACE_EXIT; | ||
757 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-vtbl.h b/drivers/char/ftape/zftape/zftape-vtbl.h new file mode 100644 index 000000000000..f31d196d1759 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-vtbl.h | |||
@@ -0,0 +1,227 @@ | |||
1 | #ifndef _ZFTAPE_VTBL_H | ||
2 | #define _ZFTAPE_VTBL_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (c) 1995-1997 Claus-Justus Heine | ||
6 | |||
7 | This program is free software; you can redistribute it and/or | ||
8 | modify it under the terms of the GNU General Public License as | ||
9 | published by the Free Software Foundation; either version 2, or (at | ||
10 | your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, but | ||
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | ||
20 | USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.h,v $ | ||
24 | * $Revision: 1.3 $ | ||
25 | * $Date: 1997/10/28 14:30:09 $ | ||
26 | * | ||
27 | * This file defines a volume table as defined in the QIC-80 | ||
28 | * development standards. | ||
29 | */ | ||
30 | |||
31 | #include <linux/list.h> | ||
32 | |||
33 | #include "../lowlevel/ftape-tracing.h" | ||
34 | |||
35 | #include "../zftape/zftape-eof.h" | ||
36 | #include "../zftape/zftape-ctl.h" | ||
37 | #include "../zftape/zftape-rw.h" | ||
38 | |||
39 | #define VTBL_SIZE 128 /* bytes */ | ||
40 | |||
41 | /* The following are offsets in the vtbl. */ | ||
42 | #define VTBL_SIG 0 | ||
43 | #define VTBL_START 4 | ||
44 | #define VTBL_END 6 | ||
45 | #define VTBL_DESC 8 | ||
46 | #define VTBL_DATE 52 | ||
47 | #define VTBL_FLAGS 56 | ||
48 | #define VTBL_FL_VENDOR_SPECIFIC (1<<0) | ||
49 | #define VTBL_FL_MUTLI_CARTRIDGE (1<<1) | ||
50 | #define VTBL_FL_NOT_VERIFIED (1<<2) | ||
51 | #define VTBL_FL_REDIR_INHIBIT (1<<3) | ||
52 | #define VTBL_FL_SEG_SPANNING (1<<4) | ||
53 | #define VTBL_FL_DIRECTORY_LAST (1<<5) | ||
54 | #define VTBL_FL_RESERVED_6 (1<<6) | ||
55 | #define VTBL_FL_RESERVED_7 (1<<7) | ||
56 | #define VTBL_M_NO 57 | ||
57 | #define VTBL_EXT 58 | ||
58 | #define EXT_ZFTAPE_SIG 0 | ||
59 | #define EXT_ZFTAPE_BLKSZ 10 | ||
60 | #define EXT_ZFTAPE_CMAP 12 | ||
61 | #define EXT_ZFTAPE_QIC113 13 | ||
62 | #define VTBL_PWD 84 | ||
63 | #define VTBL_DIR_SIZE 92 | ||
64 | #define VTBL_DATA_SIZE 96 | ||
65 | #define VTBL_OS_VERSION 104 | ||
66 | #define VTBL_SRC_DRIVE 106 | ||
67 | #define VTBL_DEV 122 | ||
68 | #define VTBL_RESERVED_1 123 | ||
69 | #define VTBL_CMPR 124 | ||
70 | #define VTBL_CMPR_UNREG 0x3f | ||
71 | #define VTBL_CMPR_USED 0x80 | ||
72 | #define VTBL_FMT 125 | ||
73 | #define VTBL_RESERVED_2 126 | ||
74 | #define VTBL_RESERVED_3 127 | ||
75 | /* compatibility with pre revision K */ | ||
76 | #define VTBL_K_CMPR 120 | ||
77 | |||
78 | /* the next is used by QIC-3020 tapes with format code 6 (>2^16 | ||
79 | * segments) It is specified in QIC-113, Rev. G, Section 5 (SCSI | ||
80 | * volume table). The difference is simply, that we only store the | ||
81 | * number of segments used, not the starting segment. | ||
82 | */ | ||
83 | #define VTBL_SCSI_SEGS 4 /* is a 4 byte value */ | ||
84 | |||
85 | /* one vtbl is 128 bytes, that results in a maximum number of | ||
86 | * 29*1024/128 = 232 volumes. | ||
87 | */ | ||
88 | #define ZFT_MAX_VOLUMES (FT_SEGMENT_SIZE/VTBL_SIZE) | ||
89 | #define VTBL_ID "VTBL" | ||
90 | #define VTBL_IDS { VTBL_ID, "XTBL", "UTID", "EXVT" } /* other valid ids */ | ||
91 | #define ZFT_VOL_NAME "zftape volume" /* volume label used by me */ | ||
92 | #define ZFTAPE_SIG "LINUX ZFT" | ||
93 | |||
94 | /* global variables | ||
95 | */ | ||
96 | typedef struct zft_internal_vtbl | ||
97 | { | ||
98 | struct list_head node; | ||
99 | int count; | ||
100 | unsigned int start_seg; /* 32 bits are enough for now */ | ||
101 | unsigned int end_seg; /* 32 bits are enough for now */ | ||
102 | __s64 size; /* uncompressed size */ | ||
103 | unsigned int blk_sz; /* block size for this volume */ | ||
104 | unsigned int zft_volume :1; /* zftape created this volume */ | ||
105 | unsigned int use_compression:1; /* compressed volume */ | ||
106 | unsigned int qic113 :1; /* layout of compressed block | ||
107 | * info and vtbl conforms to | ||
108 | * QIC-113, Rev. G | ||
109 | */ | ||
110 | unsigned int new_volume :1; /* it was created by us, this | ||
111 | * run. this allows the | ||
112 | * fields that aren't really | ||
113 | * used by zftape to be filled | ||
114 | * in by some user level | ||
115 | * program. | ||
116 | */ | ||
117 | unsigned int open :1; /* just in progress of being | ||
118 | * written | ||
119 | */ | ||
120 | } zft_volinfo; | ||
121 | |||
122 | extern struct list_head zft_vtbl; | ||
123 | #define zft_head_vtbl list_entry(zft_vtbl.next, zft_volinfo, node) | ||
124 | #define zft_eom_vtbl list_entry(zft_vtbl.prev, zft_volinfo, node) | ||
125 | #define zft_last_vtbl list_entry(zft_eom_vtbl->node.prev, zft_volinfo, node) | ||
126 | #define zft_first_vtbl list_entry(zft_head_vtbl->node.next, zft_volinfo, node) | ||
127 | #define zft_vtbl_empty (zft_eom_vtbl->node.prev == &zft_head_vtbl->node) | ||
128 | |||
129 | #define DUMP_VOLINFO(level, desc, info) \ | ||
130 | { \ | ||
131 | char tmp[21]; \ | ||
132 | strlcpy(tmp, desc, sizeof(tmp)); \ | ||
133 | TRACE(level, "Volume %d:\n" \ | ||
134 | KERN_INFO "description : %s\n" \ | ||
135 | KERN_INFO "first segment: %d\n" \ | ||
136 | KERN_INFO "last segment: %d\n" \ | ||
137 | KERN_INFO "size : " LL_X "\n" \ | ||
138 | KERN_INFO "block size : %d\n" \ | ||
139 | KERN_INFO "compression : %d\n" \ | ||
140 | KERN_INFO "zftape volume: %d\n" \ | ||
141 | KERN_INFO "QIC-113 conf.: %d", \ | ||
142 | (info)->count, tmp, (info)->start_seg, (info)->end_seg, \ | ||
143 | LL((info)->size), (info)->blk_sz, \ | ||
144 | (info)->use_compression != 0, (info)->zft_volume != 0, \ | ||
145 | (info)->qic113 != 0); \ | ||
146 | } | ||
147 | |||
148 | extern int zft_qic_mode; | ||
149 | extern int zft_old_ftape; | ||
150 | extern int zft_volume_table_changed; | ||
151 | |||
152 | /* exported functions */ | ||
153 | extern void zft_init_vtbl (void); | ||
154 | extern void zft_free_vtbl (void); | ||
155 | extern int zft_extract_volume_headers(__u8 *buffer); | ||
156 | extern int zft_update_volume_table (unsigned int segment); | ||
157 | extern int zft_open_volume (zft_position *pos, | ||
158 | int blk_sz, int use_compression); | ||
159 | extern int zft_close_volume (zft_position *pos); | ||
160 | extern const zft_volinfo *zft_find_volume(unsigned int seg_pos); | ||
161 | extern int zft_skip_volumes (int count, zft_position *pos); | ||
162 | extern __s64 zft_get_eom_pos (void); | ||
163 | extern void zft_skip_to_eom (zft_position *pos); | ||
164 | extern int zft_fake_volume_headers (eof_mark_union *eof_map, | ||
165 | int num_failed_sectors); | ||
166 | extern int zft_weof (unsigned int count, zft_position *pos); | ||
167 | extern void zft_move_past_eof (zft_position *pos); | ||
168 | |||
169 | static inline int zft_tape_at_eod (const zft_position *pos); | ||
170 | static inline int zft_tape_at_lbot (const zft_position *pos); | ||
171 | static inline void zft_position_before_eof (zft_position *pos, | ||
172 | const zft_volinfo *volume); | ||
173 | static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, | ||
174 | const zft_position *pos); | ||
175 | |||
176 | /* this function decrements the zft_seg_pos counter if we are right | ||
177 | * at the beginning of a segment. This is to handle fsfm/bsfm -- we | ||
178 | * need to position before the eof mark. NOTE: zft_tape_pos is not | ||
179 | * changed | ||
180 | */ | ||
181 | static inline void zft_position_before_eof(zft_position *pos, | ||
182 | const zft_volinfo *volume) | ||
183 | { | ||
184 | TRACE_FUN(ft_t_flow); | ||
185 | |||
186 | if (pos->seg_pos == volume->end_seg + 1 && pos->seg_byte_pos == 0) { | ||
187 | pos->seg_pos --; | ||
188 | pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos); | ||
189 | } | ||
190 | TRACE_EXIT; | ||
191 | } | ||
192 | |||
193 | /* Mmmh. Is the position at the end of the last volume, that is right | ||
194 | * before the last EOF mark also logical an EOD condition? | ||
195 | */ | ||
196 | static inline int zft_tape_at_eod(const zft_position *pos) | ||
197 | { | ||
198 | TRACE_FUN(ft_t_any); | ||
199 | |||
200 | if (zft_qic_mode) { | ||
201 | TRACE_EXIT (pos->seg_pos >= zft_eom_vtbl->start_seg || | ||
202 | zft_last_vtbl->open); | ||
203 | } else { | ||
204 | TRACE_EXIT pos->seg_pos > ft_last_data_segment; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static inline int zft_tape_at_lbot(const zft_position *pos) | ||
209 | { | ||
210 | if (zft_qic_mode) { | ||
211 | return (pos->seg_pos <= zft_first_vtbl->start_seg && | ||
212 | pos->volume_pos == 0); | ||
213 | } else { | ||
214 | return (pos->seg_pos <= ft_first_data_segment && | ||
215 | pos->volume_pos == 0); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | /* This one checks for EOF. return remaing space (may be negative) | ||
220 | */ | ||
221 | static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, | ||
222 | const zft_position *pos) | ||
223 | { | ||
224 | return (__s64)(vtbl->size - pos->volume_pos); | ||
225 | } | ||
226 | |||
227 | #endif /* _ZFTAPE_VTBL_H */ | ||
diff --git a/drivers/char/ftape/zftape/zftape-write.c b/drivers/char/ftape/zftape/zftape-write.c new file mode 100644 index 000000000000..94327b8c97b9 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-write.c | |||
@@ -0,0 +1,483 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996, 1997 Claus 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 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-write.c,v $ | ||
20 | * $Revision: 1.3 $ | ||
21 | * $Date: 1997/11/06 00:50:29 $ | ||
22 | * | ||
23 | * This file contains the writing code | ||
24 | * for the QIC-117 floppy-tape driver for Linux. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | |||
30 | #include <linux/zftape.h> | ||
31 | |||
32 | #include <asm/uaccess.h> | ||
33 | |||
34 | #include "../zftape/zftape-init.h" | ||
35 | #include "../zftape/zftape-eof.h" | ||
36 | #include "../zftape/zftape-ctl.h" | ||
37 | #include "../zftape/zftape-write.h" | ||
38 | #include "../zftape/zftape-read.h" | ||
39 | #include "../zftape/zftape-rw.h" | ||
40 | #include "../zftape/zftape-vtbl.h" | ||
41 | |||
42 | /* Global vars. | ||
43 | */ | ||
44 | |||
45 | /* Local vars. | ||
46 | */ | ||
47 | static int last_write_failed; | ||
48 | static int need_flush; | ||
49 | |||
50 | void zft_prevent_flush(void) | ||
51 | { | ||
52 | need_flush = 0; | ||
53 | } | ||
54 | |||
55 | static int zft_write_header_segments(__u8* buffer) | ||
56 | { | ||
57 | int header_1_ok = 0; | ||
58 | int header_2_ok = 0; | ||
59 | unsigned int time_stamp; | ||
60 | TRACE_FUN(ft_t_noise); | ||
61 | |||
62 | TRACE_CATCH(ftape_abort_operation(),); | ||
63 | ftape_seek_to_bot(); /* prevents extra rewind */ | ||
64 | if (GET4(buffer, 0) != FT_HSEG_MAGIC) { | ||
65 | TRACE_ABORT(-EIO, ft_t_err, | ||
66 | "wrong header signature found, aborting"); | ||
67 | } | ||
68 | /* Be optimistic: */ | ||
69 | PUT4(buffer, FT_SEG_CNT, | ||
70 | zft_written_segments + GET4(buffer, FT_SEG_CNT) + 2); | ||
71 | if ((time_stamp = zft_get_time()) != 0) { | ||
72 | PUT4(buffer, FT_WR_DATE, time_stamp); | ||
73 | if (zft_label_changed) { | ||
74 | PUT4(buffer, FT_LABEL_DATE, time_stamp); | ||
75 | } | ||
76 | } | ||
77 | TRACE(ft_t_noise, | ||
78 | "writing first header segment %d", ft_header_segment_1); | ||
79 | header_1_ok = zft_verify_write_segments(ft_header_segment_1, | ||
80 | buffer, FT_SEGMENT_SIZE, | ||
81 | zft_deblock_buf) >= 0; | ||
82 | TRACE(ft_t_noise, | ||
83 | "writing second header segment %d", ft_header_segment_2); | ||
84 | header_2_ok = zft_verify_write_segments(ft_header_segment_2, | ||
85 | buffer, FT_SEGMENT_SIZE, | ||
86 | zft_deblock_buf) >= 0; | ||
87 | if (!header_1_ok) { | ||
88 | TRACE(ft_t_warn, "Warning: " | ||
89 | "update of first header segment failed"); | ||
90 | } | ||
91 | if (!header_2_ok) { | ||
92 | TRACE(ft_t_warn, "Warning: " | ||
93 | "update of second header segment failed"); | ||
94 | } | ||
95 | if (!header_1_ok && !header_2_ok) { | ||
96 | TRACE_ABORT(-EIO, ft_t_err, "Error: " | ||
97 | "update of both header segments failed."); | ||
98 | } | ||
99 | TRACE_EXIT 0; | ||
100 | } | ||
101 | |||
102 | int zft_update_header_segments(void) | ||
103 | { | ||
104 | TRACE_FUN(ft_t_noise); | ||
105 | |||
106 | /* must NOT use zft_write_protected, as it also includes the | ||
107 | * file access mode. But we also want to update when soft | ||
108 | * write protection is enabled (O_RDONLY) | ||
109 | */ | ||
110 | if (ft_write_protected || zft_old_ftape) { | ||
111 | TRACE_ABORT(0, ft_t_noise, "Tape set read-only: no update"); | ||
112 | } | ||
113 | if (!zft_header_read) { | ||
114 | TRACE_ABORT(0, ft_t_noise, "Nothing to update"); | ||
115 | } | ||
116 | if (!zft_header_changed) { | ||
117 | zft_header_changed = zft_written_segments > 0; | ||
118 | } | ||
119 | if (!zft_header_changed && !zft_volume_table_changed) { | ||
120 | TRACE_ABORT(0, ft_t_noise, "Nothing to update"); | ||
121 | } | ||
122 | TRACE(ft_t_noise, "Updating header segments"); | ||
123 | if (ftape_get_status()->fti_state == writing) { | ||
124 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
125 | } | ||
126 | TRACE_CATCH(ftape_abort_operation(),); | ||
127 | |||
128 | zft_deblock_segment = -1; /* invalidate the cache */ | ||
129 | if (zft_header_changed) { | ||
130 | TRACE_CATCH(zft_write_header_segments(zft_hseg_buf),); | ||
131 | } | ||
132 | if (zft_volume_table_changed) { | ||
133 | TRACE_CATCH(zft_update_volume_table(ft_first_data_segment),); | ||
134 | } | ||
135 | zft_header_changed = | ||
136 | zft_volume_table_changed = | ||
137 | zft_label_changed = | ||
138 | zft_written_segments = 0; | ||
139 | TRACE_CATCH(ftape_abort_operation(),); | ||
140 | ftape_seek_to_bot(); | ||
141 | TRACE_EXIT 0; | ||
142 | } | ||
143 | |||
144 | static int read_merge_buffer(int seg_pos, __u8 *buffer, int offset, int seg_sz) | ||
145 | { | ||
146 | int result = 0; | ||
147 | const ft_trace_t old_tracing = TRACE_LEVEL; | ||
148 | TRACE_FUN(ft_t_flow); | ||
149 | |||
150 | if (zft_qic_mode) { | ||
151 | /* writing in the middle of a volume is NOT allowed | ||
152 | * | ||
153 | */ | ||
154 | TRACE(ft_t_noise, "No need to read a segment"); | ||
155 | memset(buffer + offset, 0, seg_sz - offset); | ||
156 | TRACE_EXIT 0; | ||
157 | } | ||
158 | TRACE(ft_t_any, "waiting"); | ||
159 | ftape_start_writing(FT_WR_MULTI); | ||
160 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
161 | |||
162 | TRACE(ft_t_noise, "trying to read segment %d from offset %d", | ||
163 | seg_pos, offset); | ||
164 | SET_TRACE_LEVEL(ft_t_bug); | ||
165 | result = zft_fetch_segment_fraction(seg_pos, buffer, | ||
166 | FT_RD_SINGLE, | ||
167 | offset, seg_sz - offset); | ||
168 | SET_TRACE_LEVEL(old_tracing); | ||
169 | if (result != (seg_sz - offset)) { | ||
170 | TRACE(ft_t_noise, "Ignore error: read_segment() result: %d", | ||
171 | result); | ||
172 | memset(buffer + offset, 0, seg_sz - offset); | ||
173 | } | ||
174 | TRACE_EXIT 0; | ||
175 | } | ||
176 | |||
177 | /* flush the write buffer to tape and write an eof-marker at the | ||
178 | * current position if not in raw mode. This function always | ||
179 | * positions the tape before the eof-marker. _ftape_close() should | ||
180 | * then advance to the next segment. | ||
181 | * | ||
182 | * the parameter "finish_volume" describes whether to position before | ||
183 | * or after the possibly created file-mark. We always position after | ||
184 | * the file-mark when called from ftape_close() and a flush was needed | ||
185 | * (that is ftape_write() was the last tape operation before calling | ||
186 | * ftape_flush) But we always position before the file-mark when this | ||
187 | * function get's called from outside ftape_close() | ||
188 | */ | ||
189 | int zft_flush_buffers(void) | ||
190 | { | ||
191 | int result; | ||
192 | int data_remaining; | ||
193 | int this_segs_size; | ||
194 | TRACE_FUN(ft_t_flow); | ||
195 | |||
196 | TRACE(ft_t_data_flow, | ||
197 | "entered, ftape_state = %d", ftape_get_status()->fti_state); | ||
198 | if (ftape_get_status()->fti_state != writing && !need_flush) { | ||
199 | TRACE_ABORT(0, ft_t_noise, "no need for flush"); | ||
200 | } | ||
201 | zft_io_state = zft_idle; /* triggers some initializations for the | ||
202 | * read and write routines | ||
203 | */ | ||
204 | if (last_write_failed) { | ||
205 | ftape_abort_operation(); | ||
206 | TRACE_EXIT -EIO; | ||
207 | } | ||
208 | TRACE(ft_t_noise, "flushing write buffers"); | ||
209 | this_segs_size = zft_get_seg_sz(zft_pos.seg_pos); | ||
210 | if (this_segs_size == zft_pos.seg_byte_pos) { | ||
211 | zft_pos.seg_pos ++; | ||
212 | data_remaining = zft_pos.seg_byte_pos = 0; | ||
213 | } else { | ||
214 | data_remaining = zft_pos.seg_byte_pos; | ||
215 | } | ||
216 | /* If there is any data not written to tape yet, append zero's | ||
217 | * up to the end of the sector (if using compression) or merge | ||
218 | * it with the data existing on the tape Then write the | ||
219 | * segment(s) to tape. | ||
220 | */ | ||
221 | TRACE(ft_t_noise, "Position:\n" | ||
222 | KERN_INFO "seg_pos : %d\n" | ||
223 | KERN_INFO "byte pos : %d\n" | ||
224 | KERN_INFO "remaining: %d", | ||
225 | zft_pos.seg_pos, zft_pos.seg_byte_pos, data_remaining); | ||
226 | if (data_remaining > 0) { | ||
227 | do { | ||
228 | this_segs_size = zft_get_seg_sz(zft_pos.seg_pos); | ||
229 | if (this_segs_size > data_remaining) { | ||
230 | TRACE_CATCH(read_merge_buffer(zft_pos.seg_pos, | ||
231 | zft_deblock_buf, | ||
232 | data_remaining, | ||
233 | this_segs_size), | ||
234 | last_write_failed = 1); | ||
235 | } | ||
236 | result = ftape_write_segment(zft_pos.seg_pos, | ||
237 | zft_deblock_buf, | ||
238 | FT_WR_MULTI); | ||
239 | if (result != this_segs_size) { | ||
240 | TRACE(ft_t_err, "flush buffers failed"); | ||
241 | zft_pos.tape_pos -= zft_pos.seg_byte_pos; | ||
242 | zft_pos.seg_byte_pos = 0; | ||
243 | |||
244 | last_write_failed = 1; | ||
245 | TRACE_EXIT result; | ||
246 | } | ||
247 | zft_written_segments ++; | ||
248 | TRACE(ft_t_data_flow, | ||
249 | "flush, moved out buffer: %d", result); | ||
250 | /* need next segment for more data (empty segments?) | ||
251 | */ | ||
252 | if (result < data_remaining) { | ||
253 | if (result > 0) { | ||
254 | /* move remainder to buffer beginning | ||
255 | */ | ||
256 | memmove(zft_deblock_buf, | ||
257 | zft_deblock_buf + result, | ||
258 | FT_SEGMENT_SIZE - result); | ||
259 | } | ||
260 | } | ||
261 | data_remaining -= result; | ||
262 | zft_pos.seg_pos ++; | ||
263 | } while (data_remaining > 0); | ||
264 | TRACE(ft_t_any, "result: %d", result); | ||
265 | zft_deblock_segment = --zft_pos.seg_pos; | ||
266 | if (data_remaining == 0) { /* first byte next segment */ | ||
267 | zft_pos.seg_byte_pos = this_segs_size; | ||
268 | } else { /* after data previous segment, data_remaining < 0 */ | ||
269 | zft_pos.seg_byte_pos = data_remaining + result; | ||
270 | } | ||
271 | } else { | ||
272 | TRACE(ft_t_noise, "zft_deblock_buf empty"); | ||
273 | zft_pos.seg_pos --; | ||
274 | zft_pos.seg_byte_pos = zft_get_seg_sz (zft_pos.seg_pos); | ||
275 | ftape_start_writing(FT_WR_MULTI); | ||
276 | } | ||
277 | TRACE(ft_t_any, "waiting"); | ||
278 | if ((result = ftape_loop_until_writes_done()) < 0) { | ||
279 | /* that's really bad. What to to with zft_tape_pos? | ||
280 | */ | ||
281 | TRACE(ft_t_err, "flush buffers failed"); | ||
282 | } | ||
283 | TRACE(ft_t_any, "zft_seg_pos: %d, zft_seg_byte_pos: %d", | ||
284 | zft_pos.seg_pos, zft_pos.seg_byte_pos); | ||
285 | last_write_failed = | ||
286 | need_flush = 0; | ||
287 | TRACE_EXIT result; | ||
288 | } | ||
289 | |||
290 | /* return-value: the number of bytes removed from the user-buffer | ||
291 | * | ||
292 | * out: | ||
293 | * int *write_cnt: how much actually has been moved to the | ||
294 | * zft_deblock_buf | ||
295 | * int req_len : MUST NOT BE CHANGED, except at EOT, in | ||
296 | * which case it may be adjusted | ||
297 | * in : | ||
298 | * char *buff : the user buffer | ||
299 | * int buf_pos_write : copy of buf_len_wr int | ||
300 | * this_segs_size : the size in bytes of the actual segment | ||
301 | * char | ||
302 | * *zft_deblock_buf : zft_deblock_buf | ||
303 | */ | ||
304 | static int zft_simple_write(int *cnt, | ||
305 | __u8 *dst_buf, const int seg_sz, | ||
306 | const __u8 __user *src_buf, const int req_len, | ||
307 | const zft_position *pos,const zft_volinfo *volume) | ||
308 | { | ||
309 | int space_left; | ||
310 | TRACE_FUN(ft_t_flow); | ||
311 | |||
312 | /* volume->size holds the tape capacity while volume is open */ | ||
313 | if (pos->tape_pos + volume->blk_sz > volume->size) { | ||
314 | TRACE_EXIT -ENOSPC; | ||
315 | } | ||
316 | /* remaining space in this segment, NOT zft_deblock_buf | ||
317 | */ | ||
318 | space_left = seg_sz - pos->seg_byte_pos; | ||
319 | *cnt = req_len < space_left ? req_len : space_left; | ||
320 | if (copy_from_user(dst_buf + pos->seg_byte_pos, src_buf, *cnt) != 0) { | ||
321 | TRACE_EXIT -EFAULT; | ||
322 | } | ||
323 | TRACE_EXIT *cnt; | ||
324 | } | ||
325 | |||
326 | static int check_write_access(int req_len, | ||
327 | const zft_volinfo **volume, | ||
328 | zft_position *pos, | ||
329 | const unsigned int blk_sz) | ||
330 | { | ||
331 | int result; | ||
332 | TRACE_FUN(ft_t_flow); | ||
333 | |||
334 | if ((req_len % zft_blk_sz) != 0) { | ||
335 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
336 | "write-count %d must be multiple of block-size %d", | ||
337 | req_len, blk_sz); | ||
338 | } | ||
339 | if (zft_io_state == zft_writing) { | ||
340 | /* all other error conditions have been checked earlier | ||
341 | */ | ||
342 | TRACE_EXIT 0; | ||
343 | } | ||
344 | zft_io_state = zft_idle; | ||
345 | TRACE_CATCH(zft_check_write_access(pos),); | ||
346 | /* If we haven't read the header segment yet, do it now. | ||
347 | * This will verify the configuration, get the bad sector | ||
348 | * table and read the volume table segment | ||
349 | */ | ||
350 | if (!zft_header_read) { | ||
351 | TRACE_CATCH(zft_read_header_segments(),); | ||
352 | } | ||
353 | /* fine. Now the tape is either at BOT or at EOD, | ||
354 | * Write start of volume now | ||
355 | */ | ||
356 | TRACE_CATCH(zft_open_volume(pos, blk_sz, zft_use_compression),); | ||
357 | *volume = zft_find_volume(pos->seg_pos); | ||
358 | DUMP_VOLINFO(ft_t_noise, "", *volume); | ||
359 | zft_just_before_eof = 0; | ||
360 | /* now merge with old data if necessary */ | ||
361 | if (!zft_qic_mode && pos->seg_byte_pos != 0){ | ||
362 | result = zft_fetch_segment(pos->seg_pos, | ||
363 | zft_deblock_buf, | ||
364 | FT_RD_SINGLE); | ||
365 | if (result < 0) { | ||
366 | if (result == -EINTR || result == -ENOSPC) { | ||
367 | TRACE_EXIT result; | ||
368 | } | ||
369 | TRACE(ft_t_noise, | ||
370 | "ftape_read_segment() result: %d. " | ||
371 | "This might be normal when using " | ||
372 | "a newly\nformatted tape", result); | ||
373 | memset(zft_deblock_buf, '\0', pos->seg_byte_pos); | ||
374 | } | ||
375 | } | ||
376 | zft_io_state = zft_writing; | ||
377 | TRACE_EXIT 0; | ||
378 | } | ||
379 | |||
380 | static int fill_deblock_buf(__u8 *dst_buf, const int seg_sz, | ||
381 | zft_position *pos, const zft_volinfo *volume, | ||
382 | const char __user *usr_buf, const int req_len) | ||
383 | { | ||
384 | int cnt = 0; | ||
385 | int result = 0; | ||
386 | TRACE_FUN(ft_t_flow); | ||
387 | |||
388 | if (seg_sz == 0) { | ||
389 | TRACE_ABORT(0, ft_t_data_flow, "empty segment"); | ||
390 | } | ||
391 | TRACE(ft_t_data_flow, "\n" | ||
392 | KERN_INFO "remaining req_len: %d\n" | ||
393 | KERN_INFO " buf_pos: %d", | ||
394 | req_len, pos->seg_byte_pos); | ||
395 | /* zft_deblock_buf will not contain a valid segment any longer */ | ||
396 | zft_deblock_segment = -1; | ||
397 | if (zft_use_compression) { | ||
398 | TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); | ||
399 | TRACE_CATCH(result= (*zft_cmpr_ops->write)(&cnt, | ||
400 | dst_buf, seg_sz, | ||
401 | usr_buf, req_len, | ||
402 | pos, volume),); | ||
403 | } else { | ||
404 | TRACE_CATCH(result= zft_simple_write(&cnt, | ||
405 | dst_buf, seg_sz, | ||
406 | usr_buf, req_len, | ||
407 | pos, volume),); | ||
408 | } | ||
409 | pos->volume_pos += result; | ||
410 | pos->seg_byte_pos += cnt; | ||
411 | pos->tape_pos += cnt; | ||
412 | TRACE(ft_t_data_flow, "\n" | ||
413 | KERN_INFO "removed from user-buffer : %d bytes.\n" | ||
414 | KERN_INFO "copied to zft_deblock_buf: %d bytes.\n" | ||
415 | KERN_INFO "zft_tape_pos : " LL_X " bytes.", | ||
416 | result, cnt, LL(pos->tape_pos)); | ||
417 | TRACE_EXIT result; | ||
418 | } | ||
419 | |||
420 | |||
421 | /* called by the kernel-interface routine "zft_write()" | ||
422 | */ | ||
423 | int _zft_write(const char __user *buff, int req_len) | ||
424 | { | ||
425 | int result = 0; | ||
426 | int written = 0; | ||
427 | int write_cnt; | ||
428 | int seg_sz; | ||
429 | static const zft_volinfo *volume = NULL; | ||
430 | TRACE_FUN(ft_t_flow); | ||
431 | |||
432 | zft_resid = req_len; | ||
433 | last_write_failed = 1; /* reset to 0 when successful */ | ||
434 | /* check if write is allowed | ||
435 | */ | ||
436 | TRACE_CATCH(check_write_access(req_len, &volume,&zft_pos,zft_blk_sz),); | ||
437 | while (req_len > 0) { | ||
438 | /* Allow us to escape from this loop with a signal ! | ||
439 | */ | ||
440 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
441 | seg_sz = zft_get_seg_sz(zft_pos.seg_pos); | ||
442 | if ((write_cnt = fill_deblock_buf(zft_deblock_buf, | ||
443 | seg_sz, | ||
444 | &zft_pos, | ||
445 | volume, | ||
446 | buff, | ||
447 | req_len)) < 0) { | ||
448 | zft_resid -= written; | ||
449 | if (write_cnt == -ENOSPC) { | ||
450 | /* leave the remainder to flush_buffers() | ||
451 | */ | ||
452 | TRACE(ft_t_info, "No space left on device"); | ||
453 | last_write_failed = 0; | ||
454 | if (!need_flush) { | ||
455 | need_flush = written > 0; | ||
456 | } | ||
457 | TRACE_EXIT written > 0 ? written : -ENOSPC; | ||
458 | } else { | ||
459 | TRACE_EXIT result; | ||
460 | } | ||
461 | } | ||
462 | if (zft_pos.seg_byte_pos == seg_sz) { | ||
463 | TRACE_CATCH(ftape_write_segment(zft_pos.seg_pos, | ||
464 | zft_deblock_buf, | ||
465 | FT_WR_ASYNC), | ||
466 | zft_resid -= written); | ||
467 | zft_written_segments ++; | ||
468 | zft_pos.seg_byte_pos = 0; | ||
469 | zft_deblock_segment = zft_pos.seg_pos; | ||
470 | ++zft_pos.seg_pos; | ||
471 | } | ||
472 | written += write_cnt; | ||
473 | buff += write_cnt; | ||
474 | req_len -= write_cnt; | ||
475 | } /* while (req_len > 0) */ | ||
476 | TRACE(ft_t_data_flow, "remaining in blocking buffer: %d", | ||
477 | zft_pos.seg_byte_pos); | ||
478 | TRACE(ft_t_data_flow, "just written bytes: %d", written); | ||
479 | last_write_failed = 0; | ||
480 | zft_resid -= written; | ||
481 | need_flush = need_flush || written > 0; | ||
482 | TRACE_EXIT written; /* bytes written */ | ||
483 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-write.h b/drivers/char/ftape/zftape/zftape-write.h new file mode 100644 index 000000000000..ea887015b493 --- /dev/null +++ b/drivers/char/ftape/zftape/zftape-write.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef _ZFTAPE_WRITE_H | ||
2 | #define _ZFTAPE_WRITE_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus-Justus Heine | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-write.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:13 $ | ||
25 | * | ||
26 | * This file contains the definitions for the write functions | ||
27 | * for the zftape driver for Linux. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | extern int zft_flush_buffers(void); | ||
32 | extern int zft_update_header_segments(void); | ||
33 | extern void zft_prevent_flush(void); | ||
34 | |||
35 | /* hook for the VFS interface | ||
36 | */ | ||
37 | extern int _zft_write(const char __user *buff, int req_len); | ||
38 | #endif /* _ZFTAPE_WRITE_H */ | ||
diff --git a/drivers/char/ftape/zftape/zftape_syms.c b/drivers/char/ftape/zftape/zftape_syms.c new file mode 100644 index 000000000000..2db1401682df --- /dev/null +++ b/drivers/char/ftape/zftape/zftape_syms.c | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * Copyright (C) 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 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape_syms.c,v $ | ||
20 | * $Revision: 1.3 $ | ||
21 | * $Date: 1997/10/05 19:19:14 $ | ||
22 | * | ||
23 | * This file contains the symbols that the zftape frontend to | ||
24 | * the ftape floppy tape driver exports | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | |||
29 | #include <linux/zftape.h> | ||
30 | |||
31 | #include "../zftape/zftape-init.h" | ||
32 | #include "../zftape/zftape-read.h" | ||
33 | #include "../zftape/zftape-buffers.h" | ||
34 | #include "../zftape/zftape-ctl.h" | ||
35 | |||
36 | /* zftape-init.c */ | ||
37 | EXPORT_SYMBOL(zft_cmpr_register); | ||
38 | /* zftape-read.c */ | ||
39 | EXPORT_SYMBOL(zft_fetch_segment_fraction); | ||
40 | /* zftape-buffers.c */ | ||
41 | EXPORT_SYMBOL(zft_vmalloc_once); | ||
42 | EXPORT_SYMBOL(zft_vmalloc_always); | ||
43 | EXPORT_SYMBOL(zft_vfree); | ||