2 * Copyright (C) 1996, 1997 Claus Heine
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)
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.
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.
19 * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-write.c,v $
21 * $Date: 1997/11/06 00:50:29 $
23 * This file contains the writing code
24 * for the QIC-117 floppy-tape driver for Linux.
27 #include <linux/errno.h>
30 #include <linux/zftape.h>
32 #include <asm/uaccess.h>
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"
47 static int last_write_failed
;
48 static int need_flush
;
50 void zft_prevent_flush(void)
55 static int zft_write_header_segments(__u8
* buffer
)
59 unsigned int time_stamp
;
60 TRACE_FUN(ft_t_noise
);
62 TRACE_CATCH(ftape_abort_operation(),);
63 ftape_seek_to_bot(); /* prevents extra rewind */
64 if (GET4(buffer
, 0) != FT_HSEG_MAGIC
) {
65 TRACE_ABORT(-EIO
, ft_t_err
,
66 "wrong header signature found, aborting");
69 PUT4(buffer
, FT_SEG_CNT
,
70 zft_written_segments
+ GET4(buffer
, FT_SEG_CNT
) + 2);
71 if ((time_stamp
= zft_get_time()) != 0) {
72 PUT4(buffer
, FT_WR_DATE
, time_stamp
);
73 if (zft_label_changed
) {
74 PUT4(buffer
, FT_LABEL_DATE
, time_stamp
);
78 "writing first header segment %d", ft_header_segment_1
);
79 header_1_ok
= zft_verify_write_segments(ft_header_segment_1
,
80 buffer
, FT_SEGMENT_SIZE
,
81 zft_deblock_buf
) >= 0;
83 "writing second header segment %d", ft_header_segment_2
);
84 header_2_ok
= zft_verify_write_segments(ft_header_segment_2
,
85 buffer
, FT_SEGMENT_SIZE
,
86 zft_deblock_buf
) >= 0;
88 TRACE(ft_t_warn
, "Warning: "
89 "update of first header segment failed");
92 TRACE(ft_t_warn
, "Warning: "
93 "update of second header segment failed");
95 if (!header_1_ok
&& !header_2_ok
) {
96 TRACE_ABORT(-EIO
, ft_t_err
, "Error: "
97 "update of both header segments failed.");
102 int zft_update_header_segments(void)
104 TRACE_FUN(ft_t_noise
);
106 /* must NOT use zft_write_protected, as it also includes the
107 * file access mode. But we also want to update when soft
108 * write protection is enabled (O_RDONLY)
110 if (ft_write_protected
|| zft_old_ftape
) {
111 TRACE_ABORT(0, ft_t_noise
, "Tape set read-only: no update");
113 if (!zft_header_read
) {
114 TRACE_ABORT(0, ft_t_noise
, "Nothing to update");
116 if (!zft_header_changed
) {
117 zft_header_changed
= zft_written_segments
> 0;
119 if (!zft_header_changed
&& !zft_volume_table_changed
) {
120 TRACE_ABORT(0, ft_t_noise
, "Nothing to update");
122 TRACE(ft_t_noise
, "Updating header segments");
123 if (ftape_get_status()->fti_state
== writing
) {
124 TRACE_CATCH(ftape_loop_until_writes_done(),);
126 TRACE_CATCH(ftape_abort_operation(),);
128 zft_deblock_segment
= -1; /* invalidate the cache */
129 if (zft_header_changed
) {
130 TRACE_CATCH(zft_write_header_segments(zft_hseg_buf
),);
132 if (zft_volume_table_changed
) {
133 TRACE_CATCH(zft_update_volume_table(ft_first_data_segment
),);
136 zft_volume_table_changed
=
138 zft_written_segments
= 0;
139 TRACE_CATCH(ftape_abort_operation(),);
144 static int read_merge_buffer(int seg_pos
, __u8
*buffer
, int offset
, int seg_sz
)
147 const ft_trace_t old_tracing
= TRACE_LEVEL
;
148 TRACE_FUN(ft_t_flow
);
151 /* writing in the middle of a volume is NOT allowed
154 TRACE(ft_t_noise
, "No need to read a segment");
155 memset(buffer
+ offset
, 0, seg_sz
- offset
);
158 TRACE(ft_t_any
, "waiting");
159 ftape_start_writing(FT_WR_MULTI
);
160 TRACE_CATCH(ftape_loop_until_writes_done(),);
162 TRACE(ft_t_noise
, "trying to read segment %d from offset %d",
164 SET_TRACE_LEVEL(ft_t_bug
);
165 result
= zft_fetch_segment_fraction(seg_pos
, buffer
,
167 offset
, seg_sz
- offset
);
168 SET_TRACE_LEVEL(old_tracing
);
169 if (result
!= (seg_sz
- offset
)) {
170 TRACE(ft_t_noise
, "Ignore error: read_segment() result: %d",
172 memset(buffer
+ offset
, 0, seg_sz
- offset
);
177 /* flush the write buffer to tape and write an eof-marker at the
178 * current position if not in raw mode. This function always
179 * positions the tape before the eof-marker. _ftape_close() should
180 * then advance to the next segment.
182 * the parameter "finish_volume" describes whether to position before
183 * or after the possibly created file-mark. We always position after
184 * the file-mark when called from ftape_close() and a flush was needed
185 * (that is ftape_write() was the last tape operation before calling
186 * ftape_flush) But we always position before the file-mark when this
187 * function get's called from outside ftape_close()
189 int zft_flush_buffers(void)
194 TRACE_FUN(ft_t_flow
);
196 TRACE(ft_t_data_flow
,
197 "entered, ftape_state = %d", ftape_get_status()->fti_state
);
198 if (ftape_get_status()->fti_state
!= writing
&& !need_flush
) {
199 TRACE_ABORT(0, ft_t_noise
, "no need for flush");
201 zft_io_state
= zft_idle
; /* triggers some initializations for the
202 * read and write routines
204 if (last_write_failed
) {
205 ftape_abort_operation();
208 TRACE(ft_t_noise
, "flushing write buffers");
209 this_segs_size
= zft_get_seg_sz(zft_pos
.seg_pos
);
210 if (this_segs_size
== zft_pos
.seg_byte_pos
) {
212 data_remaining
= zft_pos
.seg_byte_pos
= 0;
214 data_remaining
= zft_pos
.seg_byte_pos
;
216 /* If there is any data not written to tape yet, append zero's
217 * up to the end of the sector (if using compression) or merge
218 * it with the data existing on the tape Then write the
219 * segment(s) to tape.
221 TRACE(ft_t_noise
, "Position:\n"
222 KERN_INFO
"seg_pos : %d\n"
223 KERN_INFO
"byte pos : %d\n"
224 KERN_INFO
"remaining: %d",
225 zft_pos
.seg_pos
, zft_pos
.seg_byte_pos
, data_remaining
);
226 if (data_remaining
> 0) {
228 this_segs_size
= zft_get_seg_sz(zft_pos
.seg_pos
);
229 if (this_segs_size
> data_remaining
) {
230 TRACE_CATCH(read_merge_buffer(zft_pos
.seg_pos
,
234 last_write_failed
= 1);
236 result
= ftape_write_segment(zft_pos
.seg_pos
,
239 if (result
!= this_segs_size
) {
240 TRACE(ft_t_err
, "flush buffers failed");
241 zft_pos
.tape_pos
-= zft_pos
.seg_byte_pos
;
242 zft_pos
.seg_byte_pos
= 0;
244 last_write_failed
= 1;
247 zft_written_segments
++;
248 TRACE(ft_t_data_flow
,
249 "flush, moved out buffer: %d", result
);
250 /* need next segment for more data (empty segments?)
252 if (result
< data_remaining
) {
254 /* move remainder to buffer beginning
256 memmove(zft_deblock_buf
,
257 zft_deblock_buf
+ result
,
258 FT_SEGMENT_SIZE
- result
);
261 data_remaining
-= result
;
263 } while (data_remaining
> 0);
264 TRACE(ft_t_any
, "result: %d", result
);
265 zft_deblock_segment
= --zft_pos
.seg_pos
;
266 if (data_remaining
== 0) { /* first byte next segment */
267 zft_pos
.seg_byte_pos
= this_segs_size
;
268 } else { /* after data previous segment, data_remaining < 0 */
269 zft_pos
.seg_byte_pos
= data_remaining
+ result
;
272 TRACE(ft_t_noise
, "zft_deblock_buf empty");
274 zft_pos
.seg_byte_pos
= zft_get_seg_sz (zft_pos
.seg_pos
);
275 ftape_start_writing(FT_WR_MULTI
);
277 TRACE(ft_t_any
, "waiting");
278 if ((result
= ftape_loop_until_writes_done()) < 0) {
279 /* that's really bad. What to to with zft_tape_pos?
281 TRACE(ft_t_err
, "flush buffers failed");
283 TRACE(ft_t_any
, "zft_seg_pos: %d, zft_seg_byte_pos: %d",
284 zft_pos
.seg_pos
, zft_pos
.seg_byte_pos
);
290 /* return-value: the number of bytes removed from the user-buffer
293 * int *write_cnt: how much actually has been moved to the
295 * int req_len : MUST NOT BE CHANGED, except at EOT, in
296 * which case it may be adjusted
298 * char *buff : the user buffer
299 * int buf_pos_write : copy of buf_len_wr int
300 * this_segs_size : the size in bytes of the actual segment
302 * *zft_deblock_buf : zft_deblock_buf
304 static int zft_simple_write(int *cnt
,
305 __u8
*dst_buf
, const int seg_sz
,
306 const __u8 __user
*src_buf
, const int req_len
,
307 const zft_position
*pos
,const zft_volinfo
*volume
)
310 TRACE_FUN(ft_t_flow
);
312 /* volume->size holds the tape capacity while volume is open */
313 if (pos
->tape_pos
+ volume
->blk_sz
> volume
->size
) {
316 /* remaining space in this segment, NOT zft_deblock_buf
318 space_left
= seg_sz
- pos
->seg_byte_pos
;
319 *cnt
= req_len
< space_left
? req_len
: space_left
;
320 if (copy_from_user(dst_buf
+ pos
->seg_byte_pos
, src_buf
, *cnt
) != 0) {
326 static int check_write_access(int req_len
,
327 const zft_volinfo
**volume
,
329 const unsigned int blk_sz
)
332 TRACE_FUN(ft_t_flow
);
334 if ((req_len
% zft_blk_sz
) != 0) {
335 TRACE_ABORT(-EINVAL
, ft_t_info
,
336 "write-count %d must be multiple of block-size %d",
339 if (zft_io_state
== zft_writing
) {
340 /* all other error conditions have been checked earlier
344 zft_io_state
= zft_idle
;
345 TRACE_CATCH(zft_check_write_access(pos
),);
346 /* If we haven't read the header segment yet, do it now.
347 * This will verify the configuration, get the bad sector
348 * table and read the volume table segment
350 if (!zft_header_read
) {
351 TRACE_CATCH(zft_read_header_segments(),);
353 /* fine. Now the tape is either at BOT or at EOD,
354 * Write start of volume now
356 TRACE_CATCH(zft_open_volume(pos
, blk_sz
, zft_use_compression
),);
357 *volume
= zft_find_volume(pos
->seg_pos
);
358 DUMP_VOLINFO(ft_t_noise
, "", *volume
);
359 zft_just_before_eof
= 0;
360 /* now merge with old data if necessary */
361 if (!zft_qic_mode
&& pos
->seg_byte_pos
!= 0){
362 result
= zft_fetch_segment(pos
->seg_pos
,
366 if (result
== -EINTR
|| result
== -ENOSPC
) {
370 "ftape_read_segment() result: %d. "
371 "This might be normal when using "
372 "a newly\nformatted tape", result
);
373 memset(zft_deblock_buf
, '\0', pos
->seg_byte_pos
);
376 zft_io_state
= zft_writing
;
380 static int fill_deblock_buf(__u8
*dst_buf
, const int seg_sz
,
381 zft_position
*pos
, const zft_volinfo
*volume
,
382 const char __user
*usr_buf
, const int req_len
)
386 TRACE_FUN(ft_t_flow
);
389 TRACE_ABORT(0, ft_t_data_flow
, "empty segment");
391 TRACE(ft_t_data_flow
, "\n"
392 KERN_INFO
"remaining req_len: %d\n"
393 KERN_INFO
" buf_pos: %d",
394 req_len
, pos
->seg_byte_pos
);
395 /* zft_deblock_buf will not contain a valid segment any longer */
396 zft_deblock_segment
= -1;
397 if (zft_use_compression
) {
398 TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),);
399 TRACE_CATCH(result
= (*zft_cmpr_ops
->write
)(&cnt
,
404 TRACE_CATCH(result
= zft_simple_write(&cnt
,
409 pos
->volume_pos
+= result
;
410 pos
->seg_byte_pos
+= cnt
;
411 pos
->tape_pos
+= cnt
;
412 TRACE(ft_t_data_flow
, "\n"
413 KERN_INFO
"removed from user-buffer : %d bytes.\n"
414 KERN_INFO
"copied to zft_deblock_buf: %d bytes.\n"
415 KERN_INFO
"zft_tape_pos : " LL_X
" bytes.",
416 result
, cnt
, LL(pos
->tape_pos
));
421 /* called by the kernel-interface routine "zft_write()"
423 int _zft_write(const char __user
*buff
, int req_len
)
429 static const zft_volinfo
*volume
= NULL
;
430 TRACE_FUN(ft_t_flow
);
433 last_write_failed
= 1; /* reset to 0 when successful */
434 /* check if write is allowed
436 TRACE_CATCH(check_write_access(req_len
, &volume
,&zft_pos
,zft_blk_sz
),);
437 while (req_len
> 0) {
438 /* Allow us to escape from this loop with a signal !
440 FT_SIGNAL_EXIT(_DONT_BLOCK
);
441 seg_sz
= zft_get_seg_sz(zft_pos
.seg_pos
);
442 if ((write_cnt
= fill_deblock_buf(zft_deblock_buf
,
448 zft_resid
-= written
;
449 if (write_cnt
== -ENOSPC
) {
450 /* leave the remainder to flush_buffers()
452 TRACE(ft_t_info
, "No space left on device");
453 last_write_failed
= 0;
455 need_flush
= written
> 0;
457 TRACE_EXIT written
> 0 ? written
: -ENOSPC
;
462 if (zft_pos
.seg_byte_pos
== seg_sz
) {
463 TRACE_CATCH(ftape_write_segment(zft_pos
.seg_pos
,
466 zft_resid
-= written
);
467 zft_written_segments
++;
468 zft_pos
.seg_byte_pos
= 0;
469 zft_deblock_segment
= zft_pos
.seg_pos
;
472 written
+= write_cnt
;
474 req_len
-= write_cnt
;
475 } /* while (req_len > 0) */
476 TRACE(ft_t_data_flow
, "remaining in blocking buffer: %d",
477 zft_pos
.seg_byte_pos
);
478 TRACE(ft_t_data_flow
, "just written bytes: %d", written
);
479 last_write_failed
= 0;
480 zft_resid
-= written
;
481 need_flush
= need_flush
|| written
> 0;
482 TRACE_EXIT written
; /* bytes written */