aboutsummaryrefslogtreecommitdiff
path: root/drivers/char/ftape/zftape
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
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 00000000000..6d91c1f77c0
--- /dev/null
+++ b/drivers/char/ftape/zftape/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 1996, 1997 Claus-Justus Heine.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# $Source: /homes/cvs/ftape-stacked/ftape/zftape/Makefile,v $
+# $Revision: 1.4 $
+# $Date: 1997/10/05 19:18:58 $
+#
+# Makefile for the QIC-40/80/3010/3020 zftape interface VFS to
+# ftape
+#
+
+
+# ZFT_OBSOLETE - enable the MTIOC_ZFTAPE_GETBLKSZ ioctl. You should
+# leave this enabled for compatibility with taper.
+
+obj-$(CONFIG_ZFTAPE) += zftape.o
+
+zftape-objs := zftape-rw.o zftape-ctl.o zftape-read.o \
+ zftape-write.o zftape-vtbl.o zftape-eof.o \
+ zftape-init.o zftape-buffers.o zftape_syms.o
+
+EXTRA_CFLAGS := -DZFT_OBSOLETE
diff --git a/drivers/char/ftape/zftape/zftape-buffers.c b/drivers/char/ftape/zftape/zftape-buffers.c
new file mode 100644
index 00000000000..da06f138334
--- /dev/null
+++ b/drivers/char/ftape/zftape/zftape-buffers.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 1995-1997 Claus-Justus Heine.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ *
+ * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-buffers.c,v $
+ * $Revision: 1.2 $
+ * $Date: 1997/10/05 19:18:59 $
+ *
+ * This file contains the dynamic buffer allocation routines
+ * of zftape
+ */
+
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/zftape.h>
+
+#include <linux/vmalloc.h>
+
+#include "../zftape/zftape-init.h"
+#include "../zftape/zftape-eof.h"
+#include "../zftape/zftape-ctl.h"
+#include "../zftape/zftape-write.h"
+#include "../zftape/zftape-read.h"
+#include "../zftape/zftape-rw.h"
+#include "../zftape/zftape-vtbl.h"
+
+/* global variables
+ */
+
+/* local varibales
+ */
+static unsigned int used_memory;
+static unsigned int peak_memory;
+
+void zft_memory_stats(void)
+{
+ TRACE_FUN(ft_t_flow);
+
+ TRACE(ft_t_noise, "Memory usage (vmalloc allocations):\n"
+ KERN_INFO "total allocated: %d\n"
+ KERN_INFO "peak allocation: %d",
+ used_memory, peak_memory);
+ peak_memory = used_memory;
+ TRACE_EXIT;
+}
+
+int zft_vcalloc_once(void *new, size_t size)
+{
+ TRACE_FUN(ft_t_flow);
+ if (zft_vmalloc_once(new, size) < 0) {
+ TRACE_EXIT -ENOMEM;
+ }
+ memset(*(void **)new, '\0', size);
+ TRACE_EXIT 0;
+}
+int zft_vmalloc_once(void *new, size_t size)
+{
+ TRACE_FUN(ft_t_flow);
+
+ if (*(void **)new != NULL || size == 0) {
+ TRACE_EXIT 0;
+ }
+ if ((*(void **)new = vmalloc(size)) == NULL) {
+ TRACE_EXIT -ENOMEM;
+ }
+ used_memory += size;
+ if (peak_memory < used_memory) {
+ peak_memory = used_memory;
+ }
+ TRACE_ABORT(0, ft_t_noise,
+ "allocated buffer @ %p, %d bytes", *(void **)new, size);
+}
+int zft_vmalloc_always(void *new, size_t size)
+{
+ TRACE_FUN(ft_t_flow);
+
+ zft_vfree(new, size);
+ TRACE_EXIT zft_vmalloc_once(new, size);
+}
+void zft_vfree(void *old, size_t size)
+{
+ TRACE_FUN(ft_t_flow);
+
+ if (*(void **)old) {
+ vfree(*(void **)old);
+ used_memory -= size;
+ TRACE(ft_t_noise, "released buffer @ %p, %d bytes",
+ *(void **)old, size);
+ *(void **)old = NULL;
+ }
+ TRACE_EXIT;
+}
+
+void *zft_kmalloc(size_t size)
+{
+ void *new;
+
+ while ((new = kmalloc(size, GFP_KERNEL)) == NULL) {
+ msleep_interruptible(100);
+ }
+ memset(new, 0, size);
+ used_memory += size;
+ if (peak_memory < used_memory) {
+ peak_memory = used_memory;
+ }
+ return new;
+}
+
+void zft_kfree(void *old, size_t size)
+{
+ kfree(old);
+ used_memory -= size;
+}
+
+/* there are some more buffers that are allocated on demand.
+ * cleanup_module() calles this function to be sure to have released
+ * them
+ */
+void zft_uninit_mem(void)
+{
+ TRACE_FUN(ft_t_flow);
+
+ zft_vfree(&zft_hseg_buf, FT_SEGMENT_SIZE);
+ zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); zft_deblock_segment = -1;
+ zft_free_vtbl();
+ if (zft_cmpr_lock(0 /* don't load */) == 0) {
+ (*zft_cmpr_ops->cleanup)();
+ (*zft_cmpr_ops->reset)(); /* unlock it again */
+ }
+ zft_memory_stats();
+ TRACE_EXIT;
+}
diff --git a/drivers/char/ftape/zftape/zftape-buffers.h b/drivers/char/ftape/zftape/zftape-buffers.h
new file mode 100644
index 00000000000..798e3128c68
--- /dev/null
+++ b/drivers/char/ftape/zftape/zftape-buffers.h
@@ -0,0 +1,55 @@
+#ifndef _FTAPE_DYNMEM_H
+#define _FTAPE_DYNMEM_H
+
+/*
+ * Copyright (C) 1995-1997 Claus-Justus Heine.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ *
+ * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-buffers.h,v $
+ * $Revision: 1.2 $
+ * $Date: 1997/10/05 19:18:59 $
+ *
+ * memory allocation routines.
+ *
+ */
+
+/* we do not allocate all of the really large buffer memory before
+ * someone tries to open the drive. ftape_open() may fail with
+ * -ENOMEM, but that's better having 200k of vmalloced memory which
+ * cannot be swapped out.
+ */
+
+extern void zft_memory_stats(void);
+extern int zft_vmalloc_once(void *new, size_t size);
+extern int zft_vcalloc_once(void *new, size_t size);
+extern int zft_vmalloc_always(void *new, size_t size);
+extern void zft_vfree(void *old, size_t size);
+extern void *zft_kmalloc(size_t size);
+extern void zft_kfree(void *old, size_t size);
+
+/* called by cleanup_module()
+ */
+extern void zft_uninit_mem(void);
+
+#endif
+
+
+
+
+
+
+
diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c
new file mode 100644
index 00000000000..6c7874e5c19
--- /dev/null
+++ b/drivers/char/ftape/zftape/zftape-ctl.c
@@ -0,0 +1,1418 @@
+/*
+ * Copyright (C) 1996, 1997 Claus-Justus Heine
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ *
+ * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-ctl.c,v $
+ * $Revision: 1.2.6.2 $
+ * $Date: 1997/11/14 18:07:33 $
+ *
+ * This file contains the non-read/write zftape functions
+ * for the QIC-40/80/3010/3020 floppy-tape driver for Linux.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/fcntl.h>
+
+#include <linux/zftape.h>
+
+#include <asm/uaccess.h>
+
+#include "../zftape/zftape-init.h"
+#include "../zftape/zftape-eof.h"
+#include "../zftape/zftape-ctl.h"
+#include "../zftape/zftape-write.h"
+#include "../zftape/zftape-read.h"
+#include "../zftape/zftape-rw.h"
+#include "../zftape/zftape-vtbl.h"
+
+/* Global vars.
+ */
+int zft_write_protected; /* this is when cartridge rdonly or O_RDONLY */
+int zft_header_read;
+int zft_offline;
+unsigned int zft_unit;
+int zft_resid;
+int zft_mt_compression;
+
+/* Local vars.
+ */
+static int going_offline;
+
+typedef int (mt_fun)(int *argptr);
+typedef int (*mt_funp)(int *argptr);
+typedef struct
+{
+ mt_funp function;
+ unsigned offline : 1; /* op permitted if offline or no_tape */
+ unsigned write_protected : 1; /* op permitted if write-protected */
+ unsigned not_formatted : 1; /* op permitted if tape not formatted */
+ unsigned raw_mode : 1; /* op permitted if zft_mode == 0 */
+ unsigned need_idle_state : 1; /* need to call def_idle_state */
+ char *name;
+} fun_entry;
+
+static mt_fun mt_dummy, mt_reset, mt_fsr, mt_bsr, mt_rew, mt_offl, mt_nop,
+ mt_weof, mt_erase, mt_ras2, mt_setblk, mt_setdensity,
+ mt_seek, mt_tell, mt_reten, mt_eom, mt_fsf, mt_bsf,
+ mt_fsfm, mt_bsfm, mt_setdrvbuffer, mt_compression;
+
+static fun_entry mt_funs[]=
+{
+ {mt_reset , 1, 1, 1, 1, 0, "MT_RESET" }, /* 0 */
+ {mt_fsf , 0, 1, 0, 0, 1, "MT_FSF" },
+ {mt_bsf , 0, 1, 0, 0, 1, "MT_BSF" },
+ {mt_fsr , 0, 1, 0, 1, 1, "MT_FSR" },
+ {mt_bsr , 0, 1, 0, 1, 1, "MT_BSR" },
+ {mt_weof , 0, 0, 0, 0, 0, "MT_WEOF" }, /* 5 */
+ {mt_rew , 0, 1, 1, 1, 0, "MT_REW" },
+ {mt_offl , 0, 1, 1, 1, 0, "MT_OFFL" },
+ {mt_nop , 1, 1, 1, 1, 0, "MT_NOP" },
+ {mt_reten , 0, 1, 1, 1, 0, "MT_RETEN" },
+ {mt_bsfm , 0, 1, 0, 0, 1, "MT_BSFM" }, /* 10 */
+ {mt_fsfm , 0, 1, 0, 0, 1, "MT_FSFM" },
+ {mt_eom , 0, 1, 0, 0, 1, "MT_EOM" },
+ {mt_erase , 0, 0, 0, 1, 0, "MT_ERASE" },
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS1" },
+ {mt_ras2 , 0, 0, 0, 1, 0, "MT_RAS2" },
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS3" },
+ {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" },
+ {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" },
+ {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" },
+ {mt_setblk , 1, 1, 1, 1, 1, "MT_SETBLK"}, /* 20 */
+ {mt_setdensity , 1, 1, 1, 1, 0, "MT_SETDENSITY"},
+ {mt_seek , 0, 1, 0, 1, 1, "MT_SEEK" },
+ {mt_dummy , 0, 1, 0, 1, 1, "MT_TELL" }, /* wr-only ?! */
+ {mt_setdrvbuffer, 1, 1, 1, 1, 0, "MT_SETDRVBUFFER" },
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_FSS" }, /* 25 */
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_BSS" },
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_WSM" },
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_LOCK" },
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOCK"},
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_LOAD" }, /* 30 */
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOAD"},
+ {mt_compression , 1, 1, 1, 0, 1, "MT_COMPRESSION"},
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_SETPART"},
+ {mt_dummy , 1, 1, 1, 1, 0, "MT_MKPART"}
+};
+
+#define NR_MT_CMDS NR_ITEMS(mt_funs)
+
+void zft_reset_position(zft_position *pos)
+{
+ TRACE_FUN(ft_t_flow);
+
+ pos->seg_byte_pos =
+ pos->volume_pos = 0;
+ if (zft_header_read) {
+ /* need to keep track of the volume table and
+ * compression map. We therefor simply
+ * position at the beginning of the first
+ * volume. This covers old ftape archives as
+ * well has various flavours of the
+ * compression map segments. The worst case is
+ * that the compression map shows up as a
+ * additional volume in front of all others.
+ */
+ pos->seg_pos = zft_find_volume(0)->start_seg;
+ pos->tape_pos = zft_calc_tape_pos(pos->seg_pos);
+ } else {
+ pos->tape_pos = 0;
+ pos->seg_pos = -1;
+ }
+ zft_just_before_eof = 0;
+ zft_deblock_segment = -1;
+ zft_io_state = zft_idle;
+ zft_zap_read_buffers();
+ zft_prevent_flush();
+ /* unlock the compresison module if it is loaded.
+ * The zero arg means not to try to load the module.
+ */
+ if (zft_cmpr_lock(0) == 0) {
+ (*zft_cmpr_ops->reset)(); /* unlock */
+ }
+ TRACE_EXIT;
+}
+
+static void zft_init_driver(void)
+{
+ TRACE_FUN(ft_t_flow);
+
+ zft_resid =
+ zft_header_read =
+ zft_old_ftape =
+ zft_offline =
+ zft_write_protected =
+ going_offline =
+ zft_mt_compression =
+ zft_header_changed =
+ zft_volume_table_changed =
+ zft_written_segments = 0;
+ zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ;
+ zft_reset_position(&zft_pos); /* does most of the stuff */
+ ftape_zap_read_buffers();
+ ftape_set_state(idle);
+ TRACE_EXIT;
+}
+
+int zft_def_idle_state(void)
+{
+ int result = 0;
+ TRACE_FUN(ft_t_flow);
+
+ if (!zft_header_read) {
+ result = zft_read_header_segments();
+ } else if ((result = zft_flush_buffers()) >= 0 && zft_qic_mode) {
+ /* don't move past eof
+ */
+ (void)zft_close_volume(&zft_pos);
+ }
+ if (ftape_abort_operation() < 0) {
+ TRACE(ft_t_warn, "ftape_abort_operation() failed");
+ result = -EIO;
+ }
+ /* clear remaining read buffers */
+ zft_zap_read_buffers();
+ zft_io_state = zft_idle;
+ TRACE_EXIT result;
+}
+
+/*****************************************************************************
+ * *
+ * functions for the MTIOCTOP commands *
+ * *
+ *****************************************************************************/
+
+static int mt_dummy(int *dummy)
+{
+ TRACE_FUN(ft_t_flow);
+
+ TRACE_EXIT -ENOSYS;
+}
+
+static int mt_reset(int *dummy)
+{
+ TRACE_FUN(ft_t_flow);
+
+ (void)ftape_seek_to_bot();
+ TRACE_CATCH(ftape_reset_drive(),
+ zft_init_driver(); zft_uninit_mem(); zft_offline = 1);
+ /* fake a re-open of the device. This will set all flage and
+ * allocate buffers as appropriate. The new tape condition will
+ * force the open routine to do anything we need.
+ */
+ TRACE_CATCH(_zft_open(-1 /* fake reopen */, 0 /* dummy */),);
+ TRACE_EXIT 0;
+}
+
+static int mt_fsf(int *arg)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ result = zft_skip_volumes(*arg, &zft_pos);
+ zft_just_before_eof = 0;
+ TRACE_EXIT result;
+}
+
+static int mt_bsf(int *arg)
+{
+ int result = 0;
+ TRACE_FUN(ft_t_flow);
+
+ if (*arg != 0) {
+ result = zft_skip_volumes(-*arg + 1, &zft_pos);
+ }
+ TRACE_EXIT result;
+}
+
+static int seek_block(__s64 data_offset,
+ __s64 block_increment,
+ zft_position *pos)
+{
+ int result = 0;
+ __s64 new_block_pos;
+ __s64 vol_block_count;
+ const zft_volinfo *volume;
+ int exceed;
+ TRACE_FUN(ft_t_flow);
+
+ volume = zft_find_volume(pos->seg_pos);
+ if (volume->start_seg == 0 || volume->end_seg == 0) {
+ TRACE_EXIT -EIO;
+ }
+ new_block_pos = (zft_div_blksz(data_offset, volume->blk_sz)
+ + block_increment);
+ vol_block_count = zft_div_blksz(volume->size, volume->blk_sz);
+ if (new_block_pos < 0) {
+ TRACE(ft_t_noise,
+ "new_block_pos " LL_X " < 0", LL(new_block_pos));
+ zft_resid = (int)new_block_pos;
+ new_block_pos = 0;
+ exceed = 1;
+ } else if (new_block_pos > vol_block_count) {
+ TRACE(ft_t_noise,
+ "new_block_pos " LL_X " exceeds size of volume " LL_X,
+ LL(new_block_pos), LL(vol_block_count));
+ zft_resid = (int)(vol_block_count - new_block_pos);
+ new_block_pos = vol_block_count;
+ exceed = 1;
+ } else {
+ exceed = 0;
+ }
+ if (zft_use_compression && volume->use_compression) {
+ TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),);
+ result = (*zft_cmpr_ops->seek)(new_block_pos, pos, volume,
+ zft_deblock_buf);
+ pos->tape_pos = zft_calc_tape_pos(pos->seg_pos);
+ pos->tape_pos += pos->seg_byte_pos;
+ } else {
+ pos->volume_pos = zft_mul_blksz(new_block_pos, volume->blk_sz);
+ pos->tape_pos = zft_calc_tape_pos(volume->start_seg);
+ pos->tape_pos += pos->volume_pos;
+ pos->seg_pos = zft_calc_seg_byte_coord(&pos->seg_byte_pos,
+ pos->tape_pos);
+ }
+ zft_just_before_eof = volume->size == pos->volume_pos;
+ if (zft_just_before_eof) {
+ /* why this? because zft_file_no checks agains start
+ * and end segment of a volume. We do not want to
+ * advance to the next volume with this function.
+ */
+ TRACE(ft_t_noise, "set zft_just_before_eof");
+ zft_position_before_eof(pos, volume);
+ }
+ TRACE(ft_t_noise, "\n"
+ KERN_INFO "new_seg_pos : %d\n"
+ KERN_INFO "new_tape_pos: " LL_X "\n"
+ KERN_INFO "vol_size : " LL_X "\n"
+ KERN_INFO "seg_byte_pos: %d\n"
+ KERN_INFO "blk_sz : %d",
+ pos->seg_pos, LL(pos->tape_pos),
+ LL(volume->size), pos->seg_byte_pos,
+ volume->blk_sz);
+ if (!exceed) {
+ zft_resid = new_block_pos - zft_div_blksz(pos->volume_pos,
+ volume->blk_sz);
+ }
+ if (zft_resid < 0) {
+ zft_resid = -zft_resid;
+ }
+ TRACE_EXIT ((exceed || zft_resid != 0) && result >= 0) ? -EINVAL : result;
+}
+
+static int mt_fsr(int *arg)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ result = seek_block(zft_pos.volume_pos, *arg, &zft_pos);
+ TRACE_EXIT result;
+}
+
+static int mt_bsr(int *arg)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ result = seek_block(zft_pos.volume_pos, -*arg, &zft_pos);
+ TRACE_EXIT result;
+}
+
+static int mt_weof(int *arg)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ TRACE_CATCH(zft_flush_buffers(),);
+ result = zft_weof(*arg, &zft_pos);
+ TRACE_EXIT result;
+}
+
+static int mt_rew(int *dummy)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ if(zft_header_read) {
+ (void)zft_def_idle_state();
+ }
+ result = ftape_seek_to_bot();
+ zft_reset_position(&zft_pos);
+ TRACE_EXIT result;
+}
+
+static int mt_offl(int *dummy)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ going_offline= 1;
+ result = mt_rew(NULL);
+ TRACE_EXIT result;
+}
+
+static int mt_nop(int *dummy)
+{
+ TRACE_FUN(ft_t_flow);
+ /* should we set tape status?
+ */
+ if (!zft_offline) { /* offline includes no_tape */
+ (void)zft_def_idle_state();
+ }
+ TRACE_EXIT 0;
+}
+
+static int mt_reten(int *dummy)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ if(zft_header_read) {
+ (void)zft_def_idle_state();
+ }
+ result = ftape_seek_to_eot();
+ if (result >= 0) {
+ result = ftape_seek_to_bot();
+ }
+ TRACE_EXIT(result);
+}
+
+static int fsfbsfm(int arg, zft_position *pos)
+{
+ const zft_volinfo *vtbl;
+ __s64 block_pos;
+ TRACE_FUN(ft_t_flow);
+
+ /* What to do? This should seek to the next file-mark and
+ * position BEFORE. That is, a next write would just extend
+ * the current file. Well. Let's just seek to the end of the
+ * current file, if count == 1. If count > 1, then do a
+ * "mt_fsf(count - 1)", and then seek to the end of that file.
+ * If count == 0, do nothing
+ */
+ if (arg == 0) {
+ TRACE_EXIT 0;
+ }
+ zft_just_before_eof = 0;
+ TRACE_CATCH(zft_skip_volumes(arg < 0 ? arg : arg-1, pos),
+ if (arg > 0) {
+ zft_resid ++;
+ });
+ vtbl = zft_find_volume(pos->seg_pos);
+ block_pos = zft_div_blksz(vtbl->size, vtbl->blk_sz);
+ (void)seek_block(0, block_pos, pos);
+ if (pos->volume_pos != vtbl->size) {
+ zft_just_before_eof = 0;
+ zft_resid = 1;
+ /* we didn't managed to go there */
+ TRACE_ABORT(-EIO, ft_t_err,
+ "wanted file position " LL_X ", arrived at " LL_X,
+ LL(vtbl->size), LL(pos->volume_pos));
+ }
+ zft_just_before_eof = 1;
+ TRACE_EXIT 0;
+}
+
+static int mt_bsfm(int *arg)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ result = fsfbsfm(-*arg, &zft_pos);
+ TRACE_EXIT result;
+}
+
+static int mt_fsfm(int *arg)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ result = fsfbsfm(*arg, &zft_pos);
+ TRACE_EXIT result;
+}
+
+static int mt_eom(int *dummy)
+{
+ TRACE_FUN(ft_t_flow);
+
+ zft_skip_to_eom(&zft_pos);
+ TRACE_EXIT 0;
+}
+
+static int mt_erase(int *dummy)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ result = zft_erase();
+ TRACE_EXIT result;
+}
+
+static int mt_ras2(int *dummy)
+{
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ result = -ENOSYS;
+ TRACE_EXIT result;
+}
+
+/* Sets the new blocksize in BYTES
+ *
+ */
+static int mt_setblk(int *new_size)
+{
+ TRACE_FUN(ft_t_flow);
+
+ if((unsigned int)(*new_size) > ZFT_MAX_BLK_SZ) {
+ TRACE_ABORT(-EINVAL, ft_t_info,
+ "desired blk_sz (%d) should be <= %d bytes",
+ *new_size, ZFT_MAX_BLK_SZ);
+ }
+ if ((*new_size & (FT_SECTOR_SIZE-1)) != 0) {
+ TRACE_ABORT(-EINVAL, ft_t_info,
+ "desired blk_sz (%d) must be a multiple of %d bytes",
+ *new_size, FT_SECTOR_SIZE);
+ }
+ if (*new_size == 0) {
+ if (zft_use_compression) {
+ TRACE_ABORT(-EINVAL, ft_t_info,
+ "Variable block size not yet "
+ "supported with compression");
+ }
+ *new_size = 1;
+ }
+ zft_blk_sz = *new_size;
+ TRACE_EXIT 0;
+}
+
+static int mt_setdensity(int *arg)
+{
+ TRACE_FUN(ft_t_flow);
+
+ SET_TRACE_LEVEL(*arg);
+ TRACE(TRACE_LEVEL, "tracing set to %d", TRACE_LEVEL);
+ if ((int)TRACE_LEVEL != *arg) {
+ TRACE_EXIT -EINVAL;
+ }
+ TRACE_EXIT 0;
+}
+
+static int mt_seek(int *new_block_pos)
+{
+ int result= 0;
+ TRACE_FUN(ft_t_any);
+
+ result = seek_block(0, (__s64)*new_block_pos, &zft_pos);
+ TRACE_EXIT result;
+}
+
+/* OK, this is totally different from SCSI, but the worst thing that can
+ * happen is that there is not enough defragmentated memory that can be
+ * allocated. Also, there is a hardwired limit of 16 dma buffers in the
+ * stock ftape module. This shouldn't bring the system down.
+ *
+ * NOTE: the argument specifies the total number of dma buffers to use.
+ * The driver needs at least 3 buffers to function at all.
+ *
+ */
+static int mt_setdrvbuffer(int *cnt)
+{
+ TRACE_FUN(ft_t_flow);
+
+ if (*cnt < 3) {
+ TRACE_EXIT -EINVAL;
+ }
+ TRACE_CATCH(ftape_set_nr_buffers(*cnt),);
+ TRACE_EXIT 0;
+}
+/* return the block position from start of volume
+ */
+static int mt_tell(int *arg)
+{
+ TRACE_FUN(ft_t_flow);
+
+ *arg = zft_div_blksz(zft_pos.volume_pos,
+ zft_find_volume(zft_pos.seg_pos)->blk_sz);
+ TRACE_EXIT 0;
+}
+
+static int mt_compression(int *arg)
+{
+ TRACE_FUN(ft_t_flow);
+
+ /* Ok. We could also check whether compression is available at
+ * all by trying to load the compression module. We could
+ * also check for a block size of 1 byte which is illegal
+ * with compression. Instead of doing it here we rely on
+ * zftape_write() to do the proper checks.
+ */
+ if ((unsigned int)*arg > 1) {
+ TRACE_EXIT -EINVAL;
+ }
+ if (*arg != 0 && zft_blk_sz == 1) { /* variable block size */
+ TRACE_ABORT(-EINVAL, ft_t_info,
+ "Compression not yet supported "
+ "with variable block size");
+ }
+ zft_mt_compression = *arg;
+ if ((zft_unit & ZFT_ZIP_MODE) == 0) {
+ zft_use_compression = zft_mt_compression;
+ }
+ TRACE_EXIT 0;
+}
+
+/* check whether write access is allowed. Write access is denied when
+ * + zft_write_protected == 1 -- this accounts for either hard write
+ * protection of the cartridge or for
+ * O_RDONLY access mode of the tape device
+ * + zft_offline == 1 -- this meany that there is either no tape
+ * or that the MTOFFLINE ioctl has been
+ * previously issued (`soft eject')
+ * + ft_formatted == 0 -- this means that the cartridge is not
+ * formatted
+ * Then we distinuguish two cases. When zft_qic_mode is TRUE, then we try
+ * to emulate a `traditional' (aka SCSI like) UN*X tape device. Therefore we
+ * deny writes when
+ * + zft_qic_mode ==1 &&
+ * (!zft_tape_at_lbot() && -- tape no at logical BOT
+ * !(zft_tape_at_eom() || -- tape not at logical EOM (or EOD)
+ * (zft_tape_at_eom() &&
+ * zft_old_ftape()))) -- we can't add new volume to tapes
+ * written by old ftape because ftape
+ * don't use the volume table
+ *
+ * when the drive is in true raw mode (aka /dev/rawft0) then we don't
+ * care about LBOT and EOM conditions. This device is intended for a
+ * user level program that wants to truly implement the QIC-80 compliance
+ * at the logical data layout level of the cartridge, i.e. implement all
+ * that volume table and volume directory stuff etc.<
+ */
+int zft_check_write_access(zft_position *pos)
+{
+ TRACE_FUN(ft_t_flow);
+
+ if (zft_offline) { /* offline includes no_tape */
+ TRACE_ABORT(-ENXIO,
+ ft_t_info, "tape is offline or no cartridge");
+ }
+ if (!ft_formatted) {
+ TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted");
+ }
+ if (zft_write_protected) {
+ TRACE_ABORT(-EACCES, ft_t_info, "cartridge write protected");
+ }
+ if (zft_qic_mode) {
+ /* check BOT condition */
+ if (!zft_tape_at_lbot(pos)) {
+ /* protect cartridges written by old ftape if
+ * not at BOT because they use the vtbl
+ * segment for storing data
+ */
+ if (zft_old_ftape) {
+ TRACE_ABORT(-EACCES, ft_t_warn,
+ "Cannot write to cartridges written by old ftape when not at BOT");
+ }
+ /* not at BOT, but allow writes at EOD, of course
+ */
+ if (!zft_tape_at_eod(pos)) {
+ TRACE_ABORT(-EACCES, ft_t_info,
+ "tape not at BOT and not at EOD");
+ }
+ }
+ /* fine. Now the tape is either at BOT or at EOD. */
+ }
+ /* or in raw mode in which case we don't care about BOT and EOD */
+ TRACE_EXIT 0;
+}
+
+/* OPEN routine called by kernel-interface code
+ *
+ * NOTE: this is also called by mt_reset() with dev_minor == -1
+ * to fake a reopen after a reset.
+ */
+int _zft_open(unsigned int dev_minor, unsigned int access_mode)
+{
+ static unsigned int tape_unit;
+ static unsigned int file_access_mode;
+ int result;
+ TRACE_FUN(ft_t_flow);
+
+ if ((int)dev_minor == -1) {
+ /* fake reopen */
+ zft_unit = tape_unit;
+ access_mode = file_access_mode;
+ zft_init_driver(); /* reset all static data to defaults */
+ } else {
+ tape_unit = dev_minor;
+ file_access_mode = access_mode;
+ if ((result = ftape_enable(FTAPE_SEL(dev_minor))) < 0) {
+ TRACE_ABORT(-ENXIO, ft_t_err,
+ "ftape_enable failed: %d", result);
+ }
+ if (ft_new_tape || ft_no_tape || !ft_formatted ||
+ (FTAPE_SEL(zft_unit) != FTAPE_SEL(dev_minor)) ||
+ (zft_unit & ZFT_RAW_MODE) != (dev_minor & ZFT_RAW_MODE)) {
+ /* reset all static data to defaults,
+ */
+ zft_init_driver();
+ }
+ zft_unit = dev_minor;
+ }
+ zft_set_flags(zft_unit); /* decode the minor bits */
+ if (zft_blk_sz == 1 && zft_use_compression) {
+ ftape_disable(); /* resets ft_no_tape */
+ TRACE_ABORT(-ENODEV, ft_t_warn, "Variable block size not yet "
+ "supported with compression");
+ }
+ /* no need for most of the buffers when no tape or not
+ * formatted. for the read/write operations, it is the
+ * regardless whether there is no tape, a not-formatted tape
+ * or the whether the driver is soft offline.
+ * Nevertheless we allow some ioctls with non-formatted tapes,
+ * like rewind and reset.
+ */
+ if (ft_no_tape || !ft_formatted) {
+ zft_uninit_mem();
+ }
+ if (ft_no_tape) {
+ zft_offline = 1; /* so we need not test two variables */
+ }
+ if ((access_mode == O_WRONLY || access_mode == O_RDWR) &&
+ (ft_write_protected || ft_no_tape)) {
+ ftape_disable(); /* resets ft_no_tape */
+ TRACE_ABORT(ft_no_tape ? -ENXIO : -EROFS,
+ ft_t_warn, "wrong access mode %s cartridge",
+ ft_no_tape ? "without a" : "with write protected");
+ }
+ zft_write_protected = (access_mode == O_RDONLY ||
+ ft_write_protected != 0);
+ if (zft_write_protected) {
+ TRACE(ft_t_noise,
+ "read only access mode: %d, "
+ "drive write protected: %d",
+ access_mode == O_RDONLY,
+ ft_write_protected != 0);
+ }