]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/char/ftape/zftape/zftape-rw.c
Linux-2.6.12-rc2
[mirror_ubuntu-artful-kernel.git] / drivers / char / ftape / zftape / zftape-rw.c
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;
45 int zft_deblock_segment = -1;
46 zft_status_enum zft_io_state = zft_idle;
47 int zft_header_changed;
48 int zft_qic113; /* conform to old specs. and old zftape */
49 int zft_use_compression;
50 zft_position zft_pos = {
51 -1, /* seg_pos */
52 0, /* seg_byte_pos */
53 0, /* tape_pos */
54 0 /* volume_pos */
55 };
56 unsigned int zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ;
57 __s64 zft_capacity;
58
59 unsigned int zft_written_segments;
60 int zft_label_changed;
61
62 /* Local vars.
63 */
64
65 unsigned 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 */
81 void 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 */
121 int 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 */
166 static int seg_pos;
167 static __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 */
225 void 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
242 int 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 */
330 int 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
372 unsigned int zft_get_time(void)
373 {
374 unsigned int date = FT_TIME_STAMP(2097, 11, 30, 23, 59, 59); /* fun */
375 return date;
376 }