File: /usr/src/linux/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     #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     
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      */
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      */
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     
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     
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      */
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     
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      */
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     
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