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