patch-2.1.66 linux/drivers/char/ftape/zftape/zftape-eof.c

Next file: linux/drivers/char/ftape/zftape/zftape-eof.h
Previous file: linux/drivers/char/ftape/zftape/zftape-ctl.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.65/linux/drivers/char/ftape/zftape/zftape-eof.c linux/drivers/char/ftape/zftape/zftape-eof.c
@@ -0,0 +1,207 @@
+/*
+ *   I use these routines just to decide when I have to fake a 
+ *   volume-table to preserve compatability to original ftape.
+ */
+/*
+ *      Copyright (C) 1994-1995 Bas Laarhoven.
+ *      
+ *      Modified for zftape 1996, 1997 Claus 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-eof.c,v $
+ * $Revision: 1.2 $
+ * $Date: 1997/10/05 19:19:02 $
+ *
+ *      This file contains the eof mark handling code
+ *      for the QIC-40/80 floppy-tape driver for Linux.
+ */
+
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <linux/zftape.h>
+
+#include "../zftape/zftape-init.h"
+#include "../zftape/zftape-rw.h"
+#include "../zftape/zftape-eof.h"
+
+/*      Global vars.
+ */
+
+/* a copy of the failed sector log from the header segment.
+ */
+eof_mark_union *zft_eof_map;
+
+/* number of eof marks (entries in bad sector log) on tape.
+ */
+int zft_nr_eof_marks = -1;
+
+
+/*      Local vars.
+ */
+
+static char linux_tape_label[] = "Linux raw format V";
+enum { 
+	min_fmt_version = 1, max_fmt_version = 2 
+};
+static unsigned ftape_fmt_version = 0;
+
+
+/* Ftape (mis)uses the bad sector log to record end-of-file marks.
+ * Initially (when the tape is erased) all entries in the bad sector
+ * log are added to the tape's bad sector map. The bad sector log then
+ * is cleared.
+ *
+ * The bad sector log normally contains entries of the form: 
+ * even 16-bit word: segment number of bad sector 
+ * odd 16-bit word: encoded date
+ * There can be a total of 448 entries (1792 bytes).
+ *
+ * My guess is that no program is using this bad sector log (the *
+ * format seems useless as there is no indication of the bad sector
+ * itself, only the segment) However, if any program does use the bad
+ * sector log, the format used by ftape will let the program think
+ * there are some bad sectors and no harm is done.
+ *  
+ * The eof mark entries that ftape stores in the bad sector log: even
+ * 16-bit word: segment number of eof mark odd 16-bit word: sector
+ * number of eof mark [1..32]
+ *  
+ * The zft_eof_map as maintained is a sorted list of eof mark entries.
+ *
+ *
+ * The tape name field in the header segments is used to store a linux
+ * tape identification string and a version number.  This way the tape
+ * can be recognized as a Linux raw format tape when using tools under
+ * other OS's.
+ *
+ * 'Wide' QIC tapes (format code 4) don't have a failed sector list
+ * anymore. That space is used for the (longer) bad sector map that
+ * now is a variable length list too.  We now store our end-of-file
+ * marker list after the bad-sector-map on tape. The list is delimited
+ * by a (__u32) 0 entry.
+ */
+
+int zft_ftape_validate_label(char *label)
+{
+	static char tmp_label[45];
+	int result = 0;
+	TRACE_FUN(ft_t_any);
+	
+	memcpy(tmp_label, label, FT_LABEL_SZ);
+	tmp_label[FT_LABEL_SZ] = '\0';
+	TRACE(ft_t_noise, "tape  label = `%s'", tmp_label);
+	ftape_fmt_version = 0;
+	if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) {
+		int pos = strlen(linux_tape_label);
+		while (label[pos] >= '0' && label[pos] <= '9') {
+			ftape_fmt_version *= 10;
+			ftape_fmt_version = label[ pos++] - '0';
+		}
+		result = (ftape_fmt_version >= min_fmt_version &&
+			  ftape_fmt_version <= max_fmt_version);
+	}
+	TRACE(ft_t_noise, "format version = %d", ftape_fmt_version);
+	TRACE_EXIT result;
+}
+
+static __u8 * find_end_of_eof_list(__u8 * ptr, __u8 * limit)
+{
+	while (ptr + 3 < limit) {
+
+#if LINUX_VERSION_CODE >= KERNEL_VER(2,0,0)
+		if (get_unaligned((__u32*)ptr)) {
+			++(__u32*)ptr;
+		} else {
+			return ptr;
+		}
+#else
+		if (*(__u32*)ptr) {
+			++(__u32*)ptr;
+		} else {
+			return ptr;
+		}
+#endif
+	}
+	return NULL;
+}
+
+void zft_ftape_extract_file_marks(__u8* address)
+{
+	int i;
+	TRACE_FUN(ft_t_any);
+	
+	zft_eof_map = NULL;
+	if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
+		__u8* end;
+		__u8* start = ftape_find_end_of_bsm_list(address);
+
+		zft_nr_eof_marks = 0;
+		if (start) {
+			start += 3; /* skip end of list mark */
+			end = find_end_of_eof_list(start, 
+						   address + FT_SEGMENT_SIZE);
+			if (end && end - start <= FT_FSL_SIZE) {
+				zft_nr_eof_marks = ((end - start) / 
+						    sizeof(eof_mark_union));
+				zft_eof_map = (eof_mark_union *)start;
+			} else {
+				TRACE(ft_t_err,
+				      "EOF Mark List is too long or damaged!");
+			}
+		} else {
+			TRACE(ft_t_err, 
+			      "Bad Sector List is too long or damaged !");
+		}
+	} else {
+		zft_eof_map = (eof_mark_union *)&address[FT_FSL];
+		zft_nr_eof_marks = GET2(address, FT_FSL_CNT);
+	}
+	TRACE(ft_t_noise, "number of file marks: %d", zft_nr_eof_marks);
+	if (ftape_fmt_version == 1) {
+		TRACE(ft_t_info, "swapping version 1 fields");
+		/* version 1 format uses swapped sector and segment
+		 * fields, correct that !  
+		 */
+		for (i = 0; i < zft_nr_eof_marks; ++i) {
+			__u16 tmp = GET2(&zft_eof_map[i].mark.segment,0);
+			PUT2(&zft_eof_map[i].mark.segment, 0, 
+			     GET2(&zft_eof_map[i].mark.date,0));
+			PUT2(&zft_eof_map[i].mark.date, 0, tmp);
+		}
+	}
+	for (i = 0; i < zft_nr_eof_marks; ++i) {
+		TRACE(ft_t_noise, "eof mark: %5d/%2d",
+			GET2(&zft_eof_map[i].mark.segment, 0), 
+			GET2(&zft_eof_map[i].mark.date,0));
+	}
+	TRACE_EXIT;
+}
+
+void zft_clear_ftape_file_marks(void)
+{
+	TRACE_FUN(ft_t_flow);
+	/*  Clear failed sector log: remove all tape marks. We
+	 *  don't use old ftape-style EOF-marks.
+	 */
+	TRACE(ft_t_info, "Clearing old ftape's eof map");
+	memset(zft_eof_map, 0, zft_nr_eof_marks * sizeof(__u32));
+	zft_nr_eof_marks = 0;
+	PUT2(zft_hseg_buf, FT_FSL_CNT, 0); /* nr of eof-marks */
+	zft_header_changed = 1;
+	zft_update_label(zft_hseg_buf);
+	TRACE_EXIT;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov