| Linux kernel & device driver programming |
| [ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] |
1 /* 1
2 * Copyright (C) 1996, 1997 Claus Heine
3
4 This program is free software; you can redist
5 it under the terms of the GNU General Public
6 the Free Software Foundation; either version
7 any later version.
8
9 This program is distributed in the hope that
10 but WITHOUT ANY WARRANTY; without even the im
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR P
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU Ge
15 along with this program; see the file COPYING
16 the Free Software Foundation, 675 Mass Ave, C
17
18 *
19 * $Source: /homes/cvs/ftape-stacked/ftape/zft
20 * $Revision: 1.3 $
21 * $Date: 1997/11/06 00:50:29 $
22 *
23 * This file contains the writing code
24 * for the QIC-117 floppy-tape driver for
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
45 /* Local vars.
46 */
47 static int last_write_failed;
48 static int need_flush;
49
50 void zft_prevent_flush(void)
51 {
52 need_flush = 0;
53 }
54
55 static int zft_write_header_segments(__u8* buf
56 {
57 int header_1_ok = 0;
58 int header_2_ok = 0;
59 unsigned int time_stamp;
60 TRACE_FUN(ft_t_noise);
61
62 TRACE_CATCH(ftape_abort_operation(),);
63 ftape_seek_to_bot(); /* prevents ex
64 if (GET4(buffer, 0) != FT_HSEG_MAGIC)
65 TRACE_ABORT(-EIO, ft_t_err,
66 "wrong header sign
67 }
68 /* Be optimistic: */
69 PUT4(buffer, FT_SEG_CNT,
70 zft_written_segments + GET4(buffe
71 if ((time_stamp = zft_get_time()) != 0
72 PUT4(buffer, FT_WR_DATE, time_
73 if (zft_label_changed) {
74 PUT4(buffer, FT_LABEL_
75 }
76 }
77 TRACE(ft_t_noise,
78 "writing first header segment %d
79 header_1_ok = zft_verify_write_segment
80
81
82 TRACE(ft_t_noise,
83 "writing second header segment %
84 header_2_ok = zft_verify_write_segment
85
86
87 if (!header_1_ok) {
88 TRACE(ft_t_warn, "Warning: "
89 "update of first header
90 }
91 if (!header_2_ok) {
92 TRACE(ft_t_warn, "Warning: "
93 "update of second header
94 }
95 if (!header_1_ok && !header_2_ok) {
96 TRACE_ABORT(-EIO, ft_t_err, "E
97 "update of both header s
98 }
99 TRACE_EXIT 0;
100 }
101
102 int zft_update_header_segments(void)
103 {
104 TRACE_FUN(ft_t_noise);
105
106 /* must NOT use zft_write_protected,
107 * file access mode. But we also want
108 * write protection is enabled (O_RDO
109 */
110 if (ft_write_protected || zft_old_ftap
111 TRACE_ABORT(0, ft_t_noise, "Ta
112 }
113 if (!zft_header_read) {
114 TRACE_ABORT(0, ft_t_noise, "No
115 }
116 if (!zft_header_changed) {
117 zft_header_changed = zft_writt
118 }
119 if (!zft_header_changed && !zft_volume
120 TRACE_ABORT(0, ft_t_noise, "No
121 }
122 TRACE(ft_t_noise, "Updating header seg
123 if (ftape_get_status()->fti_state == w
124 TRACE_CATCH(ftape_loop_until_w
125 }
126 TRACE_CATCH(ftape_abort_operation(),);
127
128 zft_deblock_segment = -1; /* invalidat
129 if (zft_header_changed) {
130 TRACE_CATCH(zft_write_header_s
131 }
132 if (zft_volume_table_changed) {
133 TRACE_CATCH(zft_update_volume_
134 }
135 zft_header_changed =
136 zft_volume_table_changed =
137 zft_label_changed =
138 zft_written_segments = 0;
139 TRACE_CATCH(ftape_abort_operation(),);
140 ftape_seek_to_bot();
141 TRACE_EXIT 0;
142 }
143
144 static int read_merge_buffer(int seg_pos, __u8
145 {
146 int result = 0;
147 const ft_trace_t old_tracing = TRACE_L
148 TRACE_FUN(ft_t_flow);
149
150 if (zft_qic_mode) {
151 /* writing in the middle of a
152 *
153 */
154 TRACE(ft_t_noise, "No need to
155 memset(buffer + offset, 0, seg
156 TRACE_EXIT 0;
157 }
158 TRACE(ft_t_any, "waiting");
159 ftape_start_writing(FT_WR_MULTI);
160 TRACE_CATCH(ftape_loop_until_writes_do
161
162 TRACE(ft_t_noise, "trying to read segm
163 seg_pos, offset);
164 SET_TRACE_LEVEL(ft_t_bug);
165 result = zft_fetch_segment_fraction(se
166 FT
167 of
168 SET_TRACE_LEVEL(old_tracing);
169 if (result != (seg_sz - offset)) {
170 TRACE(ft_t_noise, "Ignore erro
171 result);
172 memset(buffer + offset, 0, seg
173 }
174 TRACE_EXIT 0;
175 }
176
177 /* flush the write buffer to tape and write an
178 * current position if not in raw mode. This
179 * positions the tape before the eof-marker.
180 * then advance to the next segment.
181 *
182 * the parameter "finish_volume" describes whe
183 * or after the possibly created file-mark. We
184 * the file-mark when called from ftape_close(
185 * (that is ftape_write() was the last tape op
186 * ftape_flush) But we always position before
187 * function get's called from outside ftape_cl
188 */
189 int zft_flush_buffers(void)
190 {
191 int result;
192 int data_remaining;
193 int this_segs_size;
194 TRACE_FUN(ft_t_flow);
195
196 TRACE(ft_t_data_flow,
197 "entered, ftape_state = %d", fta
198 if (ftape_get_status()->fti_state != w
199 TRACE_ABORT(0, ft_t_noise, "no
200 }
201 zft_io_state = zft_idle; /* triggers
202 * read and
203 */
204 if (last_write_failed) {
205 ftape_abort_operation();
206 TRACE_EXIT -EIO;
207 }
208 TRACE(ft_t_noise, "flushing write buff
209 this_segs_size = zft_get_seg_sz(zft_po
210 if (this_segs_size == zft_pos.seg_byte
211 zft_pos.seg_pos ++;
212 data_remaining = zft_pos.seg_b
213 } else {
214 data_remaining = zft_pos.seg_b
215 }
216 /* If there is any data not written to
217 * up to the end of the sector (if usi
218 * it with the data existing on the ta
219 * segment(s) to tape.
220 */
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_byt
226 if (data_remaining > 0) {
227 do {
228 this_segs_size = zft_g
229 if (this_segs_size > d
230 TRACE_CATCH(re
231
232
233
234 la
235 }
236 result = ftape_write_s
237
238
239 if (result != this_seg
240 TRACE(ft_t_err
241 zft_pos.tape_p
242 zft_pos.seg_by
243
244 last_write_fai
245 TRACE_EXIT res
246 }
247 zft_written_segments +
248 TRACE(ft_t_data_flow,
249 "flush, moved ou
250 /* need next segment f
251 */
252 if (result < data_rema
253 if (result > 0
254 /* mov
255 */
256 memmov
257
258
259 }
260 }
261 data_remaining -= resu
262 zft_pos.seg_pos ++;
263 } while (data_remaining > 0);
264 TRACE(ft_t_any, "result: %d",
265 zft_deblock_segment = --zft_po
266 if (data_remaining == 0) { /*
267 zft_pos.seg_byte_pos =
268 } else { /* after data previou
269 zft_pos.seg_byte_pos =
270 }
271 } else {
272 TRACE(ft_t_noise, "zft_deblock
273 zft_pos.seg_pos --;
274 zft_pos.seg_byte_pos = zft_get
275 ftape_start_writing(FT_WR_MULT
276 }
277 TRACE(ft_t_any, "waiting");
278 if ((result = ftape_loop_until_writes_
279 /* that's really bad. What to
280 */
281 TRACE(ft_t_err, "flush buffers
282 }
283 TRACE(ft_t_any, "zft_seg_pos: %d, zft_
284 zft_pos.seg_pos, zft_pos.seg_byt
285 last_write_failed =
286 need_flush = 0;
287 TRACE_EXIT result;
288 }
289
290 /* return-value: the number of bytes removed f
291 *
292 * out:
293 * int *write_cnt: how much actually has
294 * zft_deblock_buf
295 * int req_len : MUST NOT BE CHANGED, ex
296 * which case it may be a
297 * in :
298 * char *buff : the user buffer
299 * int buf_pos_write : copy of buf_len_wr
300 * this_segs_size : the size in bytes
301 * char
302 * *zft_deblock_buf : zft_deblock_buf
303 */
304 static int zft_simple_write(int *cnt,
305 __u8 *dst_buf, con
306 const __u8 __user
307 const zft_position
308 {
309 int space_left;
310 TRACE_FUN(ft_t_flow);
311
312 /* volume->size holds the tape capacit
313 if (pos->tape_pos + volume->blk_sz > v
314 TRACE_EXIT -ENOSPC;
315 }
316 /* remaining space in this segment, N
317 */
318 space_left = seg_sz - pos->seg_byte_po
319 *cnt = req_len < space_left ? req_len
320 if (copy_from_user(dst_buf + pos->seg_
321 TRACE_EXIT -EFAULT;
322 }
323 TRACE_EXIT *cnt;
324 }
325
326 static int check_write_access(int req_len,
327 const zft_volinf
328 zft_position *po
329 const unsigned i
330 {
331 int result;
332 TRACE_FUN(ft_t_flow);
333
334 if ((req_len % zft_blk_sz) != 0) {
335 TRACE_ABORT(-EINVAL, ft_t_info
336 "write-count %d mu
337 req_len, blk_sz);
338 }
339 if (zft_io_state == zft_writing) {
340 /* all other error conditions
341 */
342 TRACE_EXIT 0;
343 }
344 zft_io_state = zft_idle;
345 TRACE_CATCH(zft_check_write_access(pos
346 /* If we haven't read the header segm
347 * This will verify the configuration
348 * table and read the volume table se
349 */
350 if (!zft_header_read) {
351 TRACE_CATCH(zft_read_header_se
352 }
353 /* fine. Now the tape is either at BO
354 * Write start of volume now
355 */
356 TRACE_CATCH(zft_open_volume(pos, blk_s
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 necessar
361 if (!zft_qic_mode && pos->seg_byte_pos
362 result = zft_fetch_segment(pos
363 zft
364 FT_
365 if (result < 0) {
366 if (result == -EINTR |
367 TRACE_EXIT res
368 }
369 TRACE(ft_t_noise,
370 "ftape_read_segm
371 "This might be n
372 "a newly\nformat
373 memset(zft_deblock_buf
374 }
375 }
376 zft_io_state = zft_writing;
377 TRACE_EXIT 0;
378 }
379
380 static int fill_deblock_buf(__u8 *dst_buf, con
381 zft_position *pos,
382 const char __user
383 {
384 int cnt = 0;
385 int result = 0;
386 TRACE_FUN(ft_t_flow);
387
388 if (seg_sz == 0) {
389 TRACE_ABORT(0, ft_t_data_flow,
390 }
391 TRACE(ft_t_data_flow, "\n"
392 KERN_INFO "remaining req_len: %d
393 KERN_INFO " buf_pos: %d
394 req_len, pos->seg_byte_pos);
395 /* zft_deblock_buf will not contain a
396 zft_deblock_segment = -1;
397 if (zft_use_compression) {
398 TRACE_CATCH(zft_cmpr_lock(1 /*
399 TRACE_CATCH(result= (*zft_cmpr
400
401
402
403 } else {
404 TRACE_CATCH(result= zft_simple
405
406
407
408 }
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-buf
414 KERN_INFO "copied to zft_deblock
415 KERN_INFO "zft_tape_pos
416 result, cnt, LL(pos->tape_pos));
417 TRACE_EXIT result;
418 }
419
420
421 /* called by the kernel-interface routine "zf
422 */
423 int _zft_write(const char __user *buff, int re
424 {
425 int result = 0;
426 int written = 0;
427 int write_cnt;
428 int seg_sz;
429 static const zft_volinfo *volume = NUL
430 TRACE_FUN(ft_t_flow);
431
432 zft_resid = req_len;
433 last_write_failed = 1; /* reset to 0 w
434 /* check if write is allowed
435 */
436 TRACE_CATCH(check_write_access(req_len
437 while (req_len > 0) {
438 /* Allow us to escape from thi
439 */
440 FT_SIGNAL_EXIT(_DONT_BLOCK);
441 seg_sz = zft_get_seg_sz(zft_po
442 if ((write_cnt = fill_deblock_
443
444
445
446
447
448 zft_resid -= written;
449 if (write_cnt == -ENOS
450 /* leave the r
451 */
452 TRACE(ft_t_inf
453 last_write_fai
454 if (!need_flus
455 need_f
456 }
457 TRACE_EXIT wri
458 } else {
459 TRACE_EXIT res
460 }
461 }
462 if (zft_pos.seg_byte_pos == se
463 TRACE_CATCH(ftape_writ
464
465
466 zft_resid
467 zft_written_segments +
468 zft_pos.seg_byte_pos =
469 zft_deblock_segment =
470 ++zft_pos.seg_pos;
471 }
472 written += write_cnt;
473 buff += write_cnt;
474 req_len -= write_cnt;
475 } /* while (req_len > 0) */
476 TRACE(ft_t_data_flow, "remaining in bl
477 zft_pos.seg_byte_pos);
478 TRACE(ft_t_data_flow, "just written by
479 last_write_failed = 0;
480 zft_resid -= written;
481 need_flush = need_flush || written > 0
482 TRACE_EXIT written; /* b
483 }
484
| This page was automatically generated by the LXR engine. |