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 #include <asm/segment.h>
31
32 #include <linux/zftape.h>
33 #include "../zftape/zftape-init.h"
34 #include "../zftape/zftape-eof.h"
35 #include "../zftape/zftape-ctl.h"
36 #include "../zftape/zftape-write.h"
37 #include "../zftape/zftape-read.h"
38 #include "../zftape/zftape-rw.h"
39 #include "../zftape/zftape-vtbl.h"
40
41 /* Global vars.
42 */
43
44 __u8 *zft_deblock_buf;
45 __u8 *zft_hseg_buf;
46 int zft_deblock_segment = -1;
47 zft_status_enum zft_io_state = zft_idle;
48 int zft_header_changed;
49 int zft_bad_sector_map_changed;
50 int zft_qic113; /* conform to old specs. and old zftape */
51 int zft_use_compression;
52 zft_position zft_pos = {
53 -1, /* seg_pos */
54 0, /* seg_byte_pos */
55 0, /* tape_pos */
56 0 /* volume_pos */
57 };
58 unsigned int zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ;
59 __s64 zft_capacity;
60
61 unsigned int zft_written_segments;
62 int zft_label_changed;
63
64 /* Local vars.
65 */
66
zft_get_seg_sz(unsigned int segment)67 unsigned int zft_get_seg_sz(unsigned int segment)
68 {
69 int size;
70 TRACE_FUN(ft_t_any);
71
72 size = FT_SEGMENT_SIZE -
73 count_ones(ftape_get_bad_sector_entry(segment))*FT_SECTOR_SIZE;
74 if (size > 0) {
75 TRACE_EXIT (unsigned)size;
76 } else {
77 TRACE_EXIT 0;
78 }
79 }
80
81 /* ftape_set_flags(). Claus-Justus Heine, 1994/1995
82 */
zft_set_flags(unsigned minor_unit)83 void zft_set_flags(unsigned minor_unit)
84 {
85 TRACE_FUN(ft_t_flow);
86
87 zft_use_compression = zft_qic_mode = 0;
88 switch (minor_unit & ZFT_MINOR_OP_MASK) {
89 case (ZFT_Q80_MODE | ZFT_ZIP_MODE):
90 case ZFT_ZIP_MODE:
91 zft_use_compression = 1;
92 case 0:
93 case ZFT_Q80_MODE:
94 zft_qic_mode = 1;
95 if (zft_mt_compression) { /* override the default */
96 zft_use_compression = 1;
97 }
98 break;
99 case ZFT_RAW_MODE:
100 TRACE(ft_t_noise, "switching to raw mode");
101 break;
102 default:
103 TRACE(ft_t_warn, "Warning:\n"
104 KERN_INFO "Wrong combination of minor device bits.\n"
105 KERN_INFO "Switching to raw read-only mode.");
106 zft_write_protected = 1;
107 break;
108 }
109 TRACE_EXIT;
110 }
111
112 /* computes the segment and byte offset inside the segment
113 * corresponding to tape_pos.
114 *
115 * tape_pos gives the offset in bytes from the beginning of the
116 * ft_first_data_segment *seg_byte_pos is the offset in the current
117 * segment in bytes
118 *
119 * Of, if this routine was called often one should cache the last data
120 * pos it was called with, but actually this is only needed in
121 * ftape_seek_block(), that is, almost never.
122 */
zft_calc_seg_byte_coord(int * seg_byte_pos,__s64 tape_pos)123 int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos)
124 {
125 int segment;
126 int seg_sz;
127 TRACE_FUN(ft_t_flow);
128
129 if (tape_pos == 0) {
130 *seg_byte_pos = 0;
131 segment = ft_first_data_segment;
132 } else {
133 seg_sz = 0;
134
135 for (segment = ft_first_data_segment;
136 ((tape_pos > 0) && (segment <= ft_last_data_segment));
137 segment++) {
138 seg_sz = zft_get_seg_sz(segment);
139 tape_pos -= seg_sz;
140 }
141 if(tape_pos >= 0) {
142 /* the case tape_pos > != 0 means that the
143 * argument tape_pos lies beyond the EOT.
144 */
145 *seg_byte_pos= 0;
146 } else { /* tape_pos < 0 */
147 segment--;
148 *seg_byte_pos= tape_pos + seg_sz;
149 }
150 }
151 TRACE_EXIT(segment);
152 }
153
154 /* ftape_calc_tape_pos().
155 *
156 * computes the offset in bytes from the beginning of the
157 * ft_first_data_segment inverse to ftape_calc_seg_byte_coord
158 *
159 * We should do some caching. But how:
160 *
161 * Each time the header segments are read in, this routine is called
162 * with ft_tracks_per_tape*segments_per_track argumnet. So this should be
163 * the time to reset the cache.
164 *
165 * Also, it might be in the future that the bad sector map gets
166 * changed. -> reset the cache
167 */
168 static int seg_pos;
169 static __s64 tape_pos;
170
zft_get_capacity(void)171 __s64 zft_get_capacity(void)
172 {
173 seg_pos = ft_first_data_segment;
174 tape_pos = 0;
175
176 while (seg_pos <= ft_last_data_segment) {
177 tape_pos += zft_get_seg_sz(seg_pos ++);
178 }
179 return tape_pos;
180 }
181
zft_calc_tape_pos(int segment)182 __s64 zft_calc_tape_pos(int segment)
183 {
184 int d1, d2, d3;
185 TRACE_FUN(ft_t_any);
186
187 if (segment > ft_last_data_segment) {
188 TRACE_EXIT zft_capacity;
189 }
190 if (segment < ft_first_data_segment) {
191 TRACE_EXIT 0;
192 }
193 d2 = segment - seg_pos;
194 if (-d2 > 10) {
195 d1 = segment - ft_first_data_segment;
196 if (-d2 > d1) {
197 tape_pos = 0;
198 seg_pos = ft_first_data_segment;
199 d2 = d1;
200 }
201 }
202 if (d2 > 10) {
203 d3 = ft_last_data_segment - segment;
204 if (d2 > d3) {
205 tape_pos = zft_capacity;
206 seg_pos = ft_last_data_segment + 1;
207 d2 = -d3;
208 }
209 }
210 if (d2 > 0) {
211 while (seg_pos < segment) {
212 tape_pos += zft_get_seg_sz(seg_pos++);
213 }
214 } else {
215 while (seg_pos > segment) {
216 tape_pos -= zft_get_seg_sz(--seg_pos);
217 }
218 }
219 TRACE(ft_t_noise, "new cached pos: %d", seg_pos);
220
221 TRACE_EXIT tape_pos;
222 }
223
224 /* copy Z-label string to buffer, keeps track of the correct offset in
225 * `buffer'
226 */
zft_update_label(__u8 * buffer)227 void zft_update_label(__u8 *buffer)
228 {
229 TRACE_FUN(ft_t_flow);
230
231 if (strncmp(&buffer[FT_LABEL], ZFTAPE_LABEL,
232 sizeof(ZFTAPE_LABEL)-1) != 0) {
233 TRACE(ft_t_info, "updating label from \"%s\" to \"%s\"",
234 &buffer[FT_LABEL], ZFTAPE_LABEL);
235 strcpy(&buffer[FT_LABEL], ZFTAPE_LABEL);
236 memset(&buffer[FT_LABEL] + sizeof(ZFTAPE_LABEL) - 1, ' ',
237 FT_LABEL_SZ - sizeof(ZFTAPE_LABEL + 1));
238 PUT4(buffer, FT_LABEL_DATE, 0);
239 zft_label_changed = zft_header_changed = 1; /* changed */
240 }
241 TRACE_EXIT;
242 }
243
zft_verify_write_segments(unsigned int segment,__u8 * data,size_t size,__u8 * buffer)244 int zft_verify_write_segments(unsigned int segment,
245 __u8 *data, size_t size,
246 __u8 *buffer)
247 {
248 int result;
249 __u8 *write_buf;
250 __u8 *src_buf;
251 int single;
252 int seg_pos;
253 int seg_sz;
254 int remaining;
255 ft_write_mode_t write_mode;
256 TRACE_FUN(ft_t_flow);
257
258 seg_pos = segment;
259 seg_sz = zft_get_seg_sz(seg_pos);
260 src_buf = data;
261 single = size <= seg_sz;
262 remaining = size;
263 do {
264 TRACE(ft_t_noise, "\n"
265 KERN_INFO "remaining: %d\n"
266 KERN_INFO "seg_sz : %d\n"
267 KERN_INFO "segment : %d",
268 remaining, seg_sz, seg_pos);
269 if (remaining == seg_sz) {
270 write_buf = src_buf;
271 write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI;
272 remaining = 0;
273 } else if (remaining > seg_sz) {
274 write_buf = src_buf;
275 write_mode = FT_WR_ASYNC; /* don't start tape */
276 remaining -= seg_sz;
277 } else { /* remaining < seg_sz */
278 write_buf = buffer;
279 memcpy(write_buf, src_buf, remaining);
280 memset(&write_buf[remaining],'\0',seg_sz-remaining);
281 write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI;
282 remaining = 0;
283 }
284 if ((result = ftape_write_segment(seg_pos,
285 write_buf,
286 write_mode)) != seg_sz) {
287 TRACE(ft_t_err, "Error: "
288 "Couldn't write segment %d", seg_pos);
289 TRACE_EXIT result < 0 ? result : -EIO; /* bail out */
290 }
291 zft_written_segments ++;
292 seg_sz = zft_get_seg_sz(++seg_pos);
293 src_buf += result;
294 } while (remaining > 0);
295 if (ftape_get_status()->fti_state == writing) {
296 TRACE_CATCH(ftape_loop_until_writes_done(),);
297 TRACE_CATCH(ftape_abort_operation(),);
298 zft_prevent_flush();
299 }
300 seg_pos = segment;
301 src_buf = data;
302 remaining = size;
303 do {
304 TRACE_CATCH(result = ftape_read_segment(seg_pos, buffer,
305 single ? FT_RD_SINGLE
306 : FT_RD_AHEAD),);
307 if (memcmp(src_buf, buffer,
308 remaining > result ? result : remaining) != 0) {
309 TRACE_ABORT(-EIO, ft_t_err,
310 "Failed to verify written segment %d",
311 seg_pos);
312 }
313 remaining -= result;
314 TRACE(ft_t_noise, "verify successful:\n"
315 KERN_INFO "segment : %d\n"
316 KERN_INFO "segsize : %d\n"
317 KERN_INFO "remaining: %d",
318 seg_pos, result, remaining);
319 src_buf += seg_sz;
320 seg_pos++;
321 } while (remaining > 0);
322 TRACE_EXIT size;
323 }
324
325
326 /* zft_erase(). implemented compression-handling
327 *
328 * calculate the first data-segment when using/not using compression.
329 *
330 * update header-segment and compression-map-segment.
331 */
zft_erase(void)332 int zft_erase(void)
333 {
334 int result = 0;
335 TRACE_FUN(ft_t_flow);
336
337 if (!zft_header_read) {
338 TRACE_CATCH(zft_vmalloc_once((void **)&zft_hseg_buf,
339 FT_SEGMENT_SIZE),);
340 /* no need to read the vtbl and compression map */
341 TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),);
342 if ((zft_old_ftape =
343 zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]))) {
344 zft_ftape_extract_file_marks(zft_hseg_buf);
345 }
346 TRACE(ft_t_noise,
347 "ft_first_data_segment: %d, ft_last_data_segment: %d",
348 ft_first_data_segment, ft_last_data_segment);
349 zft_qic113 = (ft_format_code != fmt_normal &&
350 ft_format_code != fmt_1100ft &&
351 ft_format_code != fmt_425ft);
352 }
353 if (zft_old_ftape) {
354 zft_clear_ftape_file_marks();
355 zft_old_ftape = 0; /* no longer old ftape */
356 }
357 PUT2(zft_hseg_buf, FT_CMAP_START, 0);
358 zft_volume_table_changed = 1;
359 zft_capacity = zft_get_capacity();
360 zft_init_vtbl();
361 /* the rest must be done in ftape_update_header_segments
362 */
363 zft_header_read = 1;
364 zft_header_changed = 1; /* force update of timestamp */
365 result = zft_update_header_segments();
366
367 ftape_abort_operation();
368
369 zft_reset_position(&zft_pos);
370 zft_set_flags (zft_unit);
371 TRACE_EXIT result;
372 }
373
zft_get_time(void)374 unsigned int zft_get_time(void)
375 {
376 unsigned int date = FT_TIME_STAMP(2097, 11, 30, 23, 59, 59); /* fun */
377 return date;
378 }
379