Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame^] | 1 | /* |
| 2 | * I use these routines just to decide when I have to fake a |
| 3 | * volume-table to preserve compatibility to original ftape. |
| 4 | */ |
| 5 | /* |
| 6 | * Copyright (C) 1994-1995 Bas Laarhoven. |
| 7 | * |
| 8 | * Modified for zftape 1996, 1997 Claus Heine. |
| 9 | |
| 10 | This program is free software; you can redistribute it and/or modify |
| 11 | it under the terms of the GNU General Public License as published by |
| 12 | the Free Software Foundation; either version 2, or (at your option) |
| 13 | any later version. |
| 14 | |
| 15 | This program is distributed in the hope that it will be useful, |
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | GNU General Public License for more details. |
| 19 | |
| 20 | You should have received a copy of the GNU General Public License |
| 21 | along with this program; see the file COPYING. If not, write to |
| 22 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
| 23 | |
| 24 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.c,v $ |
| 25 | * $Revision: 1.2 $ |
| 26 | * $Date: 1997/10/05 19:19:02 $ |
| 27 | * |
| 28 | * This file contains the eof mark handling code |
| 29 | * for the QIC-40/80 floppy-tape driver for Linux. |
| 30 | */ |
| 31 | |
| 32 | #include <linux/string.h> |
| 33 | #include <linux/errno.h> |
| 34 | |
| 35 | #include <linux/zftape.h> |
| 36 | |
| 37 | #include "../zftape/zftape-init.h" |
| 38 | #include "../zftape/zftape-rw.h" |
| 39 | #include "../zftape/zftape-eof.h" |
| 40 | |
| 41 | /* Global vars. |
| 42 | */ |
| 43 | |
| 44 | /* a copy of the failed sector log from the header segment. |
| 45 | */ |
| 46 | eof_mark_union *zft_eof_map; |
| 47 | |
| 48 | /* number of eof marks (entries in bad sector log) on tape. |
| 49 | */ |
| 50 | int zft_nr_eof_marks = -1; |
| 51 | |
| 52 | |
| 53 | /* Local vars. |
| 54 | */ |
| 55 | |
| 56 | static char linux_tape_label[] = "Linux raw format V"; |
| 57 | enum { |
| 58 | min_fmt_version = 1, max_fmt_version = 2 |
| 59 | }; |
| 60 | static unsigned ftape_fmt_version = 0; |
| 61 | |
| 62 | |
| 63 | /* Ftape (mis)uses the bad sector log to record end-of-file marks. |
| 64 | * Initially (when the tape is erased) all entries in the bad sector |
| 65 | * log are added to the tape's bad sector map. The bad sector log then |
| 66 | * is cleared. |
| 67 | * |
| 68 | * The bad sector log normally contains entries of the form: |
| 69 | * even 16-bit word: segment number of bad sector |
| 70 | * odd 16-bit word: encoded date |
| 71 | * There can be a total of 448 entries (1792 bytes). |
| 72 | * |
| 73 | * My guess is that no program is using this bad sector log (the * |
| 74 | * format seems useless as there is no indication of the bad sector |
| 75 | * itself, only the segment) However, if any program does use the bad |
| 76 | * sector log, the format used by ftape will let the program think |
| 77 | * there are some bad sectors and no harm is done. |
| 78 | * |
| 79 | * The eof mark entries that ftape stores in the bad sector log: even |
| 80 | * 16-bit word: segment number of eof mark odd 16-bit word: sector |
| 81 | * number of eof mark [1..32] |
| 82 | * |
| 83 | * The zft_eof_map as maintained is a sorted list of eof mark entries. |
| 84 | * |
| 85 | * |
| 86 | * The tape name field in the header segments is used to store a linux |
| 87 | * tape identification string and a version number. This way the tape |
| 88 | * can be recognized as a Linux raw format tape when using tools under |
| 89 | * other OS's. |
| 90 | * |
| 91 | * 'Wide' QIC tapes (format code 4) don't have a failed sector list |
| 92 | * anymore. That space is used for the (longer) bad sector map that |
| 93 | * now is a variable length list too. We now store our end-of-file |
| 94 | * marker list after the bad-sector-map on tape. The list is delimited |
| 95 | * by a (__u32) 0 entry. |
| 96 | */ |
| 97 | |
| 98 | int zft_ftape_validate_label(char *label) |
| 99 | { |
| 100 | static char tmp_label[45]; |
| 101 | int result = 0; |
| 102 | TRACE_FUN(ft_t_any); |
| 103 | |
| 104 | memcpy(tmp_label, label, FT_LABEL_SZ); |
| 105 | tmp_label[FT_LABEL_SZ] = '\0'; |
| 106 | TRACE(ft_t_noise, "tape label = `%s'", tmp_label); |
| 107 | ftape_fmt_version = 0; |
| 108 | if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) { |
| 109 | int pos = strlen(linux_tape_label); |
| 110 | while (label[pos] >= '0' && label[pos] <= '9') { |
| 111 | ftape_fmt_version *= 10; |
| 112 | ftape_fmt_version = label[ pos++] - '0'; |
| 113 | } |
| 114 | result = (ftape_fmt_version >= min_fmt_version && |
| 115 | ftape_fmt_version <= max_fmt_version); |
| 116 | } |
| 117 | TRACE(ft_t_noise, "format version = %d", ftape_fmt_version); |
| 118 | TRACE_EXIT result; |
| 119 | } |
| 120 | |
| 121 | static __u8 * find_end_of_eof_list(__u8 * ptr, __u8 * limit) |
| 122 | { |
| 123 | while (ptr + 3 < limit) { |
| 124 | |
| 125 | if (get_unaligned((__u32*)ptr)) { |
| 126 | ptr += sizeof(__u32); |
| 127 | } else { |
| 128 | return ptr; |
| 129 | } |
| 130 | } |
| 131 | return NULL; |
| 132 | } |
| 133 | |
| 134 | void zft_ftape_extract_file_marks(__u8* address) |
| 135 | { |
| 136 | int i; |
| 137 | TRACE_FUN(ft_t_any); |
| 138 | |
| 139 | zft_eof_map = NULL; |
| 140 | if (ft_format_code == fmt_var || ft_format_code == fmt_big) { |
| 141 | __u8* end; |
| 142 | __u8* start = ftape_find_end_of_bsm_list(address); |
| 143 | |
| 144 | zft_nr_eof_marks = 0; |
| 145 | if (start) { |
| 146 | start += 3; /* skip end of list mark */ |
| 147 | end = find_end_of_eof_list(start, |
| 148 | address + FT_SEGMENT_SIZE); |
| 149 | if (end && end - start <= FT_FSL_SIZE) { |
| 150 | zft_nr_eof_marks = ((end - start) / |
| 151 | sizeof(eof_mark_union)); |
| 152 | zft_eof_map = (eof_mark_union *)start; |
| 153 | } else { |
| 154 | TRACE(ft_t_err, |
| 155 | "EOF Mark List is too long or damaged!"); |
| 156 | } |
| 157 | } else { |
| 158 | TRACE(ft_t_err, |
| 159 | "Bad Sector List is too long or damaged !"); |
| 160 | } |
| 161 | } else { |
| 162 | zft_eof_map = (eof_mark_union *)&address[FT_FSL]; |
| 163 | zft_nr_eof_marks = GET2(address, FT_FSL_CNT); |
| 164 | } |
| 165 | TRACE(ft_t_noise, "number of file marks: %d", zft_nr_eof_marks); |
| 166 | if (ftape_fmt_version == 1) { |
| 167 | TRACE(ft_t_info, "swapping version 1 fields"); |
| 168 | /* version 1 format uses swapped sector and segment |
| 169 | * fields, correct that ! |
| 170 | */ |
| 171 | for (i = 0; i < zft_nr_eof_marks; ++i) { |
| 172 | __u16 tmp = GET2(&zft_eof_map[i].mark.segment,0); |
| 173 | PUT2(&zft_eof_map[i].mark.segment, 0, |
| 174 | GET2(&zft_eof_map[i].mark.date,0)); |
| 175 | PUT2(&zft_eof_map[i].mark.date, 0, tmp); |
| 176 | } |
| 177 | } |
| 178 | for (i = 0; i < zft_nr_eof_marks; ++i) { |
| 179 | TRACE(ft_t_noise, "eof mark: %5d/%2d", |
| 180 | GET2(&zft_eof_map[i].mark.segment, 0), |
| 181 | GET2(&zft_eof_map[i].mark.date,0)); |
| 182 | } |
| 183 | TRACE_EXIT; |
| 184 | } |
| 185 | |
| 186 | void zft_clear_ftape_file_marks(void) |
| 187 | { |
| 188 | TRACE_FUN(ft_t_flow); |
| 189 | /* Clear failed sector log: remove all tape marks. We |
| 190 | * don't use old ftape-style EOF-marks. |
| 191 | */ |
| 192 | TRACE(ft_t_info, "Clearing old ftape's eof map"); |
| 193 | memset(zft_eof_map, 0, zft_nr_eof_marks * sizeof(__u32)); |
| 194 | zft_nr_eof_marks = 0; |
| 195 | PUT2(zft_hseg_buf, FT_FSL_CNT, 0); /* nr of eof-marks */ |
| 196 | zft_header_changed = 1; |
| 197 | zft_update_label(zft_hseg_buf); |
| 198 | TRACE_EXIT; |
| 199 | } |