aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ftape/zftape
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /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/Makefile36
-rw-r--r--drivers/char/ftape/zftape/zftape-buffers.c149
-rw-r--r--drivers/char/ftape/zftape/zftape-buffers.h55
-rw-r--r--drivers/char/ftape/zftape/zftape-ctl.c1418
-rw-r--r--drivers/char/ftape/zftape/zftape-ctl.h59
-rw-r--r--drivers/char/ftape/zftape/zftape-eof.c199
-rw-r--r--drivers/char/ftape/zftape/zftape-eof.h52
-rw-r--r--drivers/char/ftape/zftape/zftape-init.c403
-rw-r--r--drivers/char/ftape/zftape/zftape-init.h77
-rw-r--r--drivers/char/ftape/zftape/zftape-read.c377
-rw-r--r--drivers/char/ftape/zftape/zftape-read.h53
-rw-r--r--drivers/char/ftape/zftape/zftape-rw.c376
-rw-r--r--drivers/char/ftape/zftape/zftape-rw.h102
-rw-r--r--drivers/char/ftape/zftape/zftape-vtbl.c757
-rw-r--r--drivers/char/ftape/zftape/zftape-vtbl.h227
-rw-r--r--drivers/char/ftape/zftape/zftape-write.c483
-rw-r--r--drivers/char/ftape/zftape/zftape-write.h38
-rw-r--r--drivers/char/ftape/zftape/zftape_syms.c43
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
30obj-$(CONFIG_ZFTAPE) += zftape.o
31
32zftape-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
36EXTRA_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 */
49static unsigned int used_memory;
50static unsigned int peak_memory;
51
52void 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
64int 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}
73int 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}
90int 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}
97void 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
111void *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
126void 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 */
136void 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
36extern void zft_memory_stats(void);
37extern int zft_vmalloc_once(void *new, size_t size);
38extern int zft_vcalloc_once(void *new, size_t size);
39extern int zft_vmalloc_always(void *new, size_t size);
40extern void zft_vfree(void *old, size_t size);
41extern void *zft_kmalloc(size_t size);
42extern void zft_kfree(void *old, size_t size);
43
44/* called by cleanup_module()
45 */
46extern 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 */
47int zft_write_protected; /* this is when cartridge rdonly or O_RDONLY */
48int zft_header_read;
49int zft_offline;
50unsigned int zft_unit;
51int zft_resid;
52int zft_mt_compression;
53
54/* Local vars.
55 */
56static int going_offline;
57
58typedef int (mt_fun)(int *argptr);
59typedef int (*mt_funp)(int *argptr);
60typedef 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
71static 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
76static 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
117void 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
153static 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
174int 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
202static int mt_dummy(int *dummy)
203{
204 TRACE_FUN(ft_t_flow);
205
206 TRACE_EXIT -ENOSYS;
207}
208
209static 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
224static 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
234static 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
245static 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
320static 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
329static 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
338static 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
348static 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
361static 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
371static 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
382static 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
397static 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
433static 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
442static 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
451static 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
459static 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
468static 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 */
480static 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
506static 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
518static 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 */
536static 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 */
548static 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
557static 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 */
608int 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 */
651int _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 */
738int _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 */
800static 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 */
846static 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 */
915static 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 */
971static 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 */
1034static 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
1063static 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 */
1091static 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
1113static 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 */
1143static 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 */
1197static 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
1211static 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 */
1268static 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 }
1310ftmtcmd_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 */
1322int _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
40extern int zft_offline;
41extern int zft_mt_compression;
42extern int zft_write_protected;
43extern int zft_header_read;
44extern unsigned int zft_unit;
45extern int zft_resid;
46
47extern void zft_reset_position(zft_position *pos);
48extern int zft_check_write_access(zft_position *pos);
49extern int zft_def_idle_state(void);
50
51/* hooks for the VFS interface
52 */
53extern int _zft_open(unsigned int dev_minor, unsigned int access_mode);
54extern int _zft_close(void);
55extern 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 */
46eof_mark_union *zft_eof_map;
47
48/* number of eof marks (entries in bad sector log) on tape.
49 */
50int zft_nr_eof_marks = -1;
51
52
53/* Local vars.
54 */
55
56static char linux_tape_label[] = "Linux raw format V";
57enum {
58 min_fmt_version = 1, max_fmt_version = 2
59};
60static 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
98int 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
121static __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
134void 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
186void 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
36typedef union {
37 ft_fsl_entry mark;
38 __u32 entry;
39} eof_mark_union;
40
41/* ftape-eof.c defined global vars.
42 */
43extern int zft_nr_eof_marks;
44extern eof_mark_union *zft_eof_map;
45
46/* ftape-eof.c defined global functions.
47 */
48extern void zft_ftape_extract_file_marks(__u8* address);
49extern int zft_ftape_validate_label(char* label);
50extern 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
48MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine "
49 "(claus@momo.math.rwth-aachen.de)");
50MODULE_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)");
54MODULE_SUPPORTED_DEVICE("char-major-27");
55MODULE_LICENSE("GPL");
56
57/* Global vars.
58 */
59struct zft_cmpr_ops *zft_cmpr_ops = NULL;
60const ftape_info *zft_status;
61
62/* Local vars.
63 */
64static unsigned long busy_flag;
65
66static 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
81static int zft_open (struct inode *ino, struct file *filep);
82static int zft_close(struct inode *ino, struct file *filep);
83static int zft_ioctl(struct inode *ino, struct file *filep,
84 unsigned int command, unsigned long arg);
85static int zft_mmap(struct file *filep, struct vm_area_struct *vma);
86static ssize_t zft_read (struct file *fp, char __user *buff,
87 size_t req_len, loff_t *ppos);
88static ssize_t zft_write(struct file *fp, const char __user *buff,
89 size_t req_len, loff_t *ppos);
90
91static 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
102static struct class_simple *zft_class;
103
104/* Open floppy tape device
105 */
106static 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(&current->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 (&current->blocked, _DO_BLOCK);
135 TRACE_EXIT 0;
136 }
137}
138
139/* Close floppy tape device
140 */
141static 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(&current->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 */
162static 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(&current->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 */
183static 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(&current->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 */
210static 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(&current->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 */
233static 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(&current->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 */
264int 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 */
278int 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
299extern 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 */
305int __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(
314KERN_INFO
315"(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n"
316KERN_INFO
317"vfs interface for ftape floppy tape driver.\n"
318KERN_INFO
319"Support for QIC-113 compatible volume table, dynamic memory allocation\n"
320KERN_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 */
372static 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
402module_init(zft_init);
403module_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
48extern const ftape_info *zft_status; /* needed for zftape-vtbl.h */
49
50#include "../zftape/zftape-vtbl.h"
51
52struct 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
69extern struct zft_cmpr_ops *zft_cmpr_ops;
70/* zftape-init.c defined global functions.
71 */
72extern int zft_cmpr_register(struct zft_cmpr_ops *new_ops);
73extern 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 */
44int zft_just_before_eof;
45
46/* Local vars.
47 */
48static int buf_len_rd;
49
50void zft_zap_read_buffers(void)
51{
52 buf_len_rd = 0;
53}
54
55int 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
94int 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 */
156static 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 */
183static 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 */
255static 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 */
296int _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 */
35extern int zft_just_before_eof;
36
37/* ftape-read.c defined global functions.
38 */
39extern void zft_zap_read_buffers(void);
40extern int zft_read_header_segments(void);
41extern 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 */
51extern 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;
45int zft_deblock_segment = -1;
46zft_status_enum zft_io_state = zft_idle;
47int zft_header_changed;
48int zft_qic113; /* conform to old specs. and old zftape */
49int zft_use_compression;
50zft_position zft_pos = {
51 -1, /* seg_pos */
52 0, /* seg_byte_pos */
53 0, /* tape_pos */
54 0 /* volume_pos */
55};
56unsigned int zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ;
57__s64 zft_capacity;
58
59unsigned int zft_written_segments;
60int zft_label_changed;
61
62/* Local vars.
63 */
64
65unsigned 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 */
81void 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 */
121int 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 */
166static int seg_pos;
167static __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 */
225void 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
242int 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 */
330int 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
372unsigned 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
59typedef enum
60{
61 zft_idle = 0,
62 zft_reading,
63 zft_writing,
64} zft_status_enum;
65
66typedef 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
76extern zft_position zft_pos;
77extern __u8 *zft_deblock_buf;
78extern __u8 *zft_hseg_buf;
79extern int zft_deblock_segment;
80extern zft_status_enum zft_io_state;
81extern int zft_header_changed;
82extern int zft_qic113; /* conform to old specs. and old zftape */
83extern int zft_use_compression;
84extern unsigned int zft_blk_sz;
85extern __s64 zft_capacity;
86extern unsigned int zft_written_segments;
87extern int zft_label_changed;
88
89/* zftape-rw.c exported functions
90 */
91extern unsigned int zft_get_seg_sz(unsigned int segment);
92extern void zft_set_flags(unsigned int minor_unit);
93extern int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos);
94extern __s64 zft_calc_tape_pos(int segment);
95extern __s64 zft_get_capacity(void);
96extern void zft_update_label(__u8 *buffer);
97extern int zft_erase(void);
98extern int zft_verify_write_segments(unsigned int segment,
99 __u8 *data, size_t size, __u8 *buffer);
100extern 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 */
49int zft_qic_mode = 1; /* use the vtbl */
50int zft_old_ftape; /* prevents old ftaped tapes to be overwritten */
51int zft_volume_table_changed; /* for write_header_segments() */
52
53/*
54 * private variables (only exported for inline functions)
55 */
56LIST_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 */
61static zft_volinfo tape_vtbl;
62static zft_volinfo eot_vtbl;
63static zft_volinfo *cur_vtbl;
64
65static 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
74void 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 */
92void 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 */
131static 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 */
150static 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 */
189static 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 */
208static 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 */
251static 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 */
288int 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 */
315static 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 */
338static 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 */
367int 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 */
437int 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
504int 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 */
549int 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 */
601void 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 */
620int 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 */
651int 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
710const 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 */
742void 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 */
96typedef 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
122extern 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
148extern int zft_qic_mode;
149extern int zft_old_ftape;
150extern int zft_volume_table_changed;
151
152/* exported functions */
153extern void zft_init_vtbl (void);
154extern void zft_free_vtbl (void);
155extern int zft_extract_volume_headers(__u8 *buffer);
156extern int zft_update_volume_table (unsigned int segment);
157extern int zft_open_volume (zft_position *pos,
158 int blk_sz, int use_compression);
159extern int zft_close_volume (zft_position *pos);
160extern const zft_volinfo *zft_find_volume(unsigned int seg_pos);
161extern int zft_skip_volumes (int count, zft_position *pos);
162extern __s64 zft_get_eom_pos (void);
163extern void zft_skip_to_eom (zft_position *pos);
164extern int zft_fake_volume_headers (eof_mark_union *eof_map,
165 int num_failed_sectors);
166extern int zft_weof (unsigned int count, zft_position *pos);
167extern void zft_move_past_eof (zft_position *pos);
168
169static inline int zft_tape_at_eod (const zft_position *pos);
170static inline int zft_tape_at_lbot (const zft_position *pos);
171static inline void zft_position_before_eof (zft_position *pos,
172 const zft_volinfo *volume);
173static 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 */
181static 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 */
196static 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
208static 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 */
221static 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 */
47static int last_write_failed;
48static int need_flush;
49
50void zft_prevent_flush(void)
51{
52 need_flush = 0;
53}
54
55static 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
102int 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
144static 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 */
189int 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 */
304static 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
326static 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
380static 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 */
423int _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
31extern int zft_flush_buffers(void);
32extern int zft_update_header_segments(void);
33extern void zft_prevent_flush(void);
34
35/* hook for the VFS interface
36 */
37extern 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 */
37EXPORT_SYMBOL(zft_cmpr_register);
38/* zftape-read.c */
39EXPORT_SYMBOL(zft_fetch_segment_fraction);
40/* zftape-buffers.c */
41EXPORT_SYMBOL(zft_vmalloc_once);
42EXPORT_SYMBOL(zft_vmalloc_always);
43EXPORT_SYMBOL(zft_vfree);