Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / char / ftape / zftape / zftape-read.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-read.c,v $
20  * $Revision: 1.2 $
21  * $Date: 1997/10/05 19:19:06 $
22  *
23  *      This file contains the high level reading code
24  *      for the QIC-117 floppy-tape driver for Linux.
25  */
26
27 #include <linux/errno.h>
28 #include <linux/mm.h>
29
30 #include <linux/zftape.h>
31
32 #include <asm/uaccess.h>
33
34 #include "../zftape/zftape-init.h"
35 #include "../zftape/zftape-eof.h"
36 #include "../zftape/zftape-ctl.h"
37 #include "../zftape/zftape-write.h"
38 #include "../zftape/zftape-read.h"
39 #include "../zftape/zftape-rw.h"
40 #include "../zftape/zftape-vtbl.h"
41
42 /*      Global vars.
43  */
44 int zft_just_before_eof;
45
46 /*      Local vars.
47  */
48 static int buf_len_rd;
49
50 void zft_zap_read_buffers(void)
51 {
52         buf_len_rd = 0;
53 }
54
55 int zft_read_header_segments(void)      
56 {
57         TRACE_FUN(ft_t_flow);
58
59         zft_header_read = 0;
60         TRACE_CATCH(zft_vmalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),);
61         TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),);
62         TRACE(ft_t_info, "Segments written since first format: %d",
63               (int)GET4(zft_hseg_buf, FT_SEG_CNT));
64         zft_qic113 = (ft_format_code != fmt_normal &&
65                       ft_format_code != fmt_1100ft &&
66                       ft_format_code != fmt_425ft);
67         TRACE(ft_t_info, "ft_first_data_segment: %d, ft_last_data_segment: %d", 
68               ft_first_data_segment, ft_last_data_segment);
69         zft_capacity = zft_get_capacity();
70         zft_old_ftape = zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]);
71         if (zft_old_ftape) {
72                 TRACE(ft_t_info, 
73 "Found old ftaped tape, emulating eof marks, entering read-only mode");
74                 zft_ftape_extract_file_marks(zft_hseg_buf);
75                 TRACE_CATCH(zft_fake_volume_headers(zft_eof_map, 
76                                                     zft_nr_eof_marks),);
77         } else {
78                 /* the specs say that the volume table must be
79                  * initialized with zeroes during formatting, so it
80                  * MUST be readable, i.e. contain vaid ECC
81                  * information.  
82                  */
83                 TRACE_CATCH(ftape_read_segment(ft_first_data_segment, 
84                                                zft_deblock_buf, 
85                                                FT_RD_SINGLE),);
86                 TRACE_CATCH(zft_extract_volume_headers(zft_deblock_buf),);
87         }
88         zft_header_read = 1;
89         zft_set_flags(zft_unit);
90         zft_reset_position(&zft_pos);
91         TRACE_EXIT 0;
92 }
93
94 int zft_fetch_segment_fraction(const unsigned int segment, void *buffer,
95                                const ft_read_mode_t read_mode,
96                                const unsigned int start,
97                                const unsigned int size)
98 {
99         int seg_sz;
100         TRACE_FUN(ft_t_flow);
101
102         if (segment == zft_deblock_segment) {
103                 TRACE(ft_t_data_flow,
104                       "re-using segment %d already in deblock buffer",
105                       segment);
106                 seg_sz = zft_get_seg_sz(segment);
107                 if (start > seg_sz) {
108                         TRACE_ABORT(-EINVAL, ft_t_bug,
109                                     "trying to read beyond end of segment:\n"
110                                     KERN_INFO "seg_sz : %d\n"
111                                     KERN_INFO "start  : %d\n"
112                                     KERN_INFO "segment: %d",
113                                     seg_sz, start, segment);
114                 }
115                 if ((start + size) > seg_sz) {
116                         TRACE_EXIT seg_sz - start;
117                 }
118                 TRACE_EXIT size;
119         }
120         seg_sz = ftape_read_segment_fraction(segment, buffer, read_mode,
121                                              start, size);
122         TRACE(ft_t_data_flow, "segment %d, result %d", segment, seg_sz);
123         if ((int)seg_sz >= 0 && start == 0 && size == FT_SEGMENT_SIZE) {
124                 /*  this implicitly assumes that we are always called with
125                  *  buffer == zft_deblock_buf 
126                  */
127                 zft_deblock_segment = segment;
128         } else {
129                 zft_deblock_segment = -1;
130         }
131         TRACE_EXIT seg_sz;
132 }
133
134 /*
135  * out:
136  *
137  * int *read_cnt: the number of bytes we removed from the
138  *                zft_deblock_buf (result)
139  *
140  * int *to_do   : the remaining size of the read-request. Is changed.
141  *
142  * in:
143  *
144  * char *buff      : buff is the address of the upper part of the user
145  *                   buffer, that hasn't been filled with data yet.
146  * int buf_pos_read: copy of buf_pos_rd
147  * int buf_len_read: copy of buf_len_rd
148  * char *zft_deblock_buf: ftape_zft_deblock_buf
149  *
150  * returns the amount of data actually copied to the user-buffer
151  *
152  * to_do MUST NOT SHRINK except to indicate an EOT. In this case to_do
153  * has to be set to 0. We cannot return -ENOSPC, because we return the
154  * amount of data actually * copied to the user-buffer
155  */
156 static int zft_simple_read (int *read_cnt, 
157                             __u8  __user *dst_buf, 
158                             const int to_do, 
159                             const __u8 *src_buf, 
160                             const int seg_sz, 
161                             const zft_position *pos,
162                             const zft_volinfo *volume)
163 {
164         TRACE_FUN(ft_t_flow);
165
166         if (seg_sz - pos->seg_byte_pos < to_do) {
167                 *read_cnt = seg_sz - pos->seg_byte_pos;
168         } else {
169                 *read_cnt = to_do;
170         }
171         if (copy_to_user(dst_buf, 
172                          src_buf + pos->seg_byte_pos, *read_cnt) != 0) {
173                 TRACE_EXIT -EFAULT;
174         }
175         TRACE(ft_t_noise, "nr bytes just read: %d", *read_cnt);
176         TRACE_EXIT *read_cnt;
177 }
178
179 /* req_len: gets clipped due to EOT of EOF.
180  * req_clipped: is a flag indicating whether req_len was clipped or not
181  * volume: contains information on current volume (blk_sz etc.)
182  */
183 static int check_read_access(int *req_len, 
184                              const zft_volinfo **volume,
185                              int *req_clipped, 
186                              const zft_position *pos)
187 {
188         static __s64 remaining;
189         static int eod;
190         TRACE_FUN(ft_t_flow);
191         
192         if (zft_io_state != zft_reading) {
193                 if (zft_offline) { /* offline includes no_tape */
194                         TRACE_ABORT(-ENXIO, ft_t_warn,
195                                     "tape is offline or no cartridge");
196                 }
197                 if (!ft_formatted) {
198                         TRACE_ABORT(-EACCES,
199                                     ft_t_warn, "tape is not formatted");
200                 }
201                 /*  now enter defined state, read header segment if not
202                  *  already done and flush write buffers
203                  */
204                 TRACE_CATCH(zft_def_idle_state(),);
205                 zft_io_state = zft_reading;
206                 if (zft_tape_at_eod(pos)) {
207                         eod = 1;
208                         TRACE_EXIT 1;
209                 }
210                 eod = 0;
211                 *volume = zft_find_volume(pos->seg_pos);
212                 /* get the space left until EOF */
213                 remaining = zft_check_for_eof(*volume, pos);
214                 buf_len_rd = 0;
215                 TRACE(ft_t_noise, "remaining: " LL_X ", vol_no: %d",
216                       LL(remaining), (*volume)->count);
217         } else if (zft_tape_at_eod(pos)) {
218                 if (++eod > 2) {
219                         TRACE_EXIT -EIO; /* st.c also returns -EIO */
220                 } else {
221                         TRACE_EXIT 1;
222                 }
223         }
224         if ((*req_len % (*volume)->blk_sz) != 0) {
225                 /*  this message is informational only. The user gets the
226                  *  proper return value
227                  */
228                 TRACE_ABORT(-EINVAL, ft_t_info,
229                             "req_len %d not a multiple of block size %d",
230                             *req_len, (*volume)->blk_sz);
231         }
232         /* As GNU tar doesn't accept partial read counts when the
233          * multiple volume flag is set, we make sure to return the
234          * requested amount of data. Except, of course, at the end of
235          * the tape or file mark.  
236          */
237         remaining -= *req_len;
238         if (remaining <= 0) {
239                 TRACE(ft_t_noise, 
240                       "clipped request from %d to %d.", 
241                       *req_len, (int)(*req_len + remaining));
242                 *req_len += remaining;
243                 *req_clipped = 1;
244         } else {
245                 *req_clipped = 0;
246         }
247         TRACE_EXIT 0;
248 }
249
250 /* this_segs_size: the current segment's size.
251  * buff: the USER-SPACE buffer provided by the calling function.
252  * req_len: how much data should be read at most.
253  * volume: contains information on current volume (blk_sz etc.)
254  */  
255 static int empty_deblock_buf(__u8 __user *usr_buf, const int req_len,
256                              const __u8 *src_buf, const int seg_sz,
257                              zft_position *pos,
258                              const zft_volinfo *volume)
259 {
260         int cnt;
261         int result = 0;
262         TRACE_FUN(ft_t_flow);
263
264         TRACE(ft_t_data_flow, "this_segs_size: %d", seg_sz);
265         if (zft_use_compression && volume->use_compression) {
266                 TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),);
267                 TRACE_CATCH(result= (*zft_cmpr_ops->read)(&cnt,
268                                                           usr_buf, req_len,
269                                                           src_buf, seg_sz,
270                                                           pos, volume),);
271         } else {                                  
272                 TRACE_CATCH(result= zft_simple_read (&cnt,
273                                                      usr_buf, req_len,
274                                                      src_buf, seg_sz,
275                                                      pos, volume),);
276         }
277         pos->volume_pos   += result;
278         pos->tape_pos     += cnt;
279         pos->seg_byte_pos += cnt;
280         buf_len_rd        -= cnt; /* remaining bytes in buffer */
281         TRACE(ft_t_data_flow, "buf_len_rd: %d, cnt: %d", buf_len_rd, cnt);
282         if(pos->seg_byte_pos >= seg_sz) {
283                 pos->seg_pos++;
284                 pos->seg_byte_pos = 0;
285         }
286         TRACE(ft_t_data_flow, "bytes moved out of deblock-buffer: %d", cnt);
287         TRACE_EXIT result;
288 }
289
290
291 /* note: we store the segment id of the segment that is inside the
292  * deblock buffer. This spares a lot of ftape_read_segment()s when we
293  * use small block-sizes. The block-size may be 1kb (SECTOR_SIZE). In
294  * this case a MTFSR 28 maybe still inside the same segment.
295  */
296 int _zft_read(char __user *buff, int req_len)
297 {
298         int req_clipped;
299         int result     = 0;
300         int bytes_read = 0;
301         static unsigned int seg_sz = 0;
302         static const zft_volinfo *volume = NULL;
303         TRACE_FUN(ft_t_flow);
304         
305         zft_resid = req_len;
306         result = check_read_access(&req_len, &volume,
307                                    &req_clipped, &zft_pos);
308         switch(result) {
309         case 0: 
310                 break; /* nothing special */
311         case 1: 
312                 TRACE(ft_t_noise, "EOD reached");
313                 TRACE_EXIT 0;   /* EOD */
314         default:
315                 TRACE_ABORT(result, ft_t_noise,
316                             "check_read_access() failed with result %d",
317                             result);
318                 TRACE_EXIT result;
319         }
320         while (req_len > 0) { 
321                 /*  Allow escape from this loop on signal !
322                  */
323                 FT_SIGNAL_EXIT(_DONT_BLOCK);
324                 /* buf_len_rd == 0 means that we need to read a new
325                  * segment.
326                  */
327                 if (buf_len_rd == 0) {
328                         while((result = zft_fetch_segment(zft_pos.seg_pos,
329                                                           zft_deblock_buf,
330                                                           FT_RD_AHEAD)) == 0) {
331                                 zft_pos.seg_pos ++;
332                                 zft_pos.seg_byte_pos = 0;
333                         }
334                         if (result < 0) {
335                                 zft_resid -= bytes_read;
336                                 TRACE_ABORT(result, ft_t_noise,
337                                             "zft_fetch_segment(): %d",
338                                             result);
339                         }
340                         seg_sz = result;
341                         buf_len_rd = seg_sz - zft_pos.seg_byte_pos;
342                 }
343                 TRACE_CATCH(result = empty_deblock_buf(buff, 
344                                                        req_len,
345                                                        zft_deblock_buf, 
346                                                        seg_sz, 
347                                                        &zft_pos,
348                                                        volume),
349                             zft_resid -= bytes_read);
350                 TRACE(ft_t_data_flow, "bytes just read: %d", result);
351                 bytes_read += result; /* what we got so far       */
352                 buff       += result; /* index in user-buffer     */
353                 req_len    -= result; /* what's left from req_len */
354         } /* while (req_len  > 0) */
355         if (req_clipped) {
356                 TRACE(ft_t_data_flow,
357                       "maybe partial count because of eof mark");
358                 if (zft_just_before_eof && bytes_read == 0) {
359                         /* req_len was > 0, but user didn't get
360                          * anything the user has read in the eof-mark 
361                          */
362                         zft_move_past_eof(&zft_pos);
363                         ftape_abort_operation();
364                 } else {
365                         /* don't skip to the next file before the user
366                          * tried to read a second time past EOF Just
367                          * mark that we are at EOF and maybe decrement
368                          * zft_seg_pos to stay in the same volume;
369                          */
370                         zft_just_before_eof = 1;
371                         zft_position_before_eof(&zft_pos, volume);
372                         TRACE(ft_t_noise, "just before eof");
373                 }
374         }
375         zft_resid -= result; /* for MTSTATUS       */
376         TRACE_EXIT bytes_read;
377 }