2 * Copyright (C) 1993-1996 Bas Laarhoven,
3 * (C) 1996-1997 Claus-Justus Heine.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, write to
17 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20 * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-rw.c,v $
22 * $Date: 1997/10/28 14:26:49 $
24 * This file contains some common code for the segment read and
25 * segment write routines for the QIC-117 floppy-tape driver for
29 #include <linux/string.h>
30 #include <linux/errno.h>
32 #include <linux/ftape.h>
33 #include <linux/qic117.h>
34 #include "../lowlevel/ftape-tracing.h"
35 #include "../lowlevel/ftape-rw.h"
36 #include "../lowlevel/fdc-io.h"
37 #include "../lowlevel/ftape-init.h"
38 #include "../lowlevel/ftape-io.h"
39 #include "../lowlevel/ftape-ctl.h"
40 #include "../lowlevel/ftape-read.h"
41 #include "../lowlevel/ftape-ecc.h"
42 #include "../lowlevel/ftape-bsm.h"
46 int ft_nr_buffers
= 0;
47 buffer_struct
*ft_buffer
[FT_MAX_NR_BUFFERS
] = {NULL
, };
48 static volatile int ft_head
;
49 static volatile int ft_tail
; /* not volatile but need same type as head */
51 location_record ft_location
= {-1, 0};
52 volatile int ftape_tape_running
= 0;
56 static int overrun_count_offset
= 0;
57 static int inhibit_correction
= 0;
59 /* maxmimal allowed overshoot when fast seeking
61 #define OVERSHOOT_LIMIT 10
63 /* Increment cyclic buffer nr.
65 buffer_struct
*ftape_next_buffer(ft_buffer_queue_t pos
)
69 if (++ft_head
>= ft_nr_buffers
) {
72 return ft_buffer
[ft_head
];
74 if (++ft_tail
>= ft_nr_buffers
) {
77 return ft_buffer
[ft_tail
];
82 int ftape_buffer_id(ft_buffer_queue_t pos
)
85 case ft_queue_head
: return ft_head
;
86 case ft_queue_tail
: return ft_tail
;
90 buffer_struct
*ftape_get_buffer(ft_buffer_queue_t pos
)
93 case ft_queue_head
: return ft_buffer
[ft_head
];
94 case ft_queue_tail
: return ft_buffer
[ft_tail
];
98 void ftape_reset_buffer(void)
100 ft_head
= ft_tail
= 0;
103 buffer_state_enum
ftape_set_state(buffer_state_enum new_state
)
105 buffer_state_enum old_state
= ft_driver_state
;
107 ft_driver_state
= new_state
;
110 /* Calculate Floppy Disk Controller and DMA parameters for a segment.
111 * head: selects buffer struct in array.
112 * offset: number of physical sectors to skip (including bad ones).
113 * count: number of physical sectors to handle (including bad ones).
115 static int setup_segment(buffer_struct
* buff
,
117 unsigned int sector_offset
,
118 unsigned int sector_count
,
121 SectorMap offset_mask
;
125 buff
->segment_id
= segment_id
;
126 buff
->sector_offset
= sector_offset
;
127 buff
->remaining
= sector_count
;
128 buff
->head
= segment_id
/ ftape_segments_per_head
;
129 buff
->cyl
= (segment_id
% ftape_segments_per_head
) / ftape_segments_per_cylinder
;
130 buff
->sect
= (segment_id
% ftape_segments_per_cylinder
) * FT_SECTORS_PER_SEGMENT
+ 1;
132 offset_mask
= (1 << buff
->sector_offset
) - 1;
133 mask
= ftape_get_bad_sector_entry(segment_id
) & offset_mask
;
136 offset_mask
>>= 1; /* don't count bad sector */
140 buff
->data_offset
= count_ones(offset_mask
); /* good sectors to skip */
141 buff
->ptr
= buff
->address
+ buff
->data_offset
* FT_SECTOR_SIZE
;
142 TRACE(ft_t_flow
, "data offset = %d sectors", buff
->data_offset
);
144 buff
->soft_error_map
&= offset_mask
; /* keep skipped part */
146 buff
->hard_error_map
= buff
->soft_error_map
= 0;
148 buff
->bad_sector_map
= ftape_get_bad_sector_entry(buff
->segment_id
);
149 if (buff
->bad_sector_map
!= 0) {
150 TRACE(ft_t_noise
, "segment: %d, bad sector map: %08lx",
151 buff
->segment_id
, (long)buff
->bad_sector_map
);
153 TRACE(ft_t_flow
, "segment: %d", buff
->segment_id
);
155 if (buff
->sector_offset
> 0) {
156 buff
->bad_sector_map
>>= buff
->sector_offset
;
158 if (buff
->sector_offset
!= 0 || buff
->remaining
!= FT_SECTORS_PER_SEGMENT
) {
159 TRACE(ft_t_flow
, "sector offset = %d, count = %d",
160 buff
->sector_offset
, buff
->remaining
);
162 /* Segments with 3 or less sectors are not written with valid
163 * data because there is no space left for the ecc. The
164 * data written is whatever happens to be in the buffer.
165 * Reading such a segment will return a zero byte-count.
166 * To allow us to read/write segments with all bad sectors
167 * we fake one readable sector in the segment. This
168 * prevents having to handle these segments in a very
169 * special way. It is not important if the reading of this
170 * bad sector fails or not (the data is ignored). It is
171 * only read to keep the driver running.
173 * The QIC-40/80 spec. has no information on how to handle
174 * this case, so this is my interpretation.
176 if (buff
->bad_sector_map
== EMPTY_SEGMENT
) {
177 TRACE(ft_t_flow
, "empty segment %d, fake first sector good",
179 if (buff
->ptr
!= buff
->address
) {
180 TRACE(ft_t_bug
, "This is a bug: %p/%p",
181 buff
->ptr
, buff
->address
);
183 buff
->bad_sector_map
= FAKE_SEGMENT
;
186 buff
->next_segment
= segment_id
+ 1;
190 /* Calculate Floppy Disk Controller and DMA parameters for a new segment.
192 int ftape_setup_new_segment(buffer_struct
* buff
, int segment_id
, int skip
)
195 static int old_segment_id
= -1;
196 static buffer_state_enum old_ft_driver_state
= idle
;
199 int count
= FT_SECTORS_PER_SEGMENT
;
200 TRACE_FUN(ft_t_flow
);
202 TRACE(ft_t_flow
, "%s segment %d (old = %d)",
203 (ft_driver_state
== reading
|| ft_driver_state
== verifying
)
204 ? "reading" : "writing",
205 segment_id
, old_segment_id
);
206 if (ft_driver_state
!= old_ft_driver_state
) { /* when verifying */
208 old_ft_driver_state
= ft_driver_state
;
210 if (segment_id
== old_segment_id
) {
212 ++ft_history
.retries
;
213 TRACE(ft_t_flow
, "setting up for retry nr %d", buff
->retry
);
215 if (skip
&& buff
->skip
> 0) { /* allow skip on retry */
218 TRACE(ft_t_flow
, "skipping %d sectors", offset
);
223 old_segment_id
= segment_id
;
225 result
= setup_segment(buff
, segment_id
, offset
, count
, retry
);
229 /* Determine size of next cluster of good sectors.
231 int ftape_calc_next_cluster(buffer_struct
* buff
)
235 while (buff
->remaining
> 0 && (buff
->bad_sector_map
& 1) != 0) {
236 buff
->bad_sector_map
>>= 1;
237 ++buff
->sector_offset
;
240 /* Find next cluster of good sectors
242 if (buff
->bad_sector_map
== 0) { /* speed up */
243 buff
->sector_count
= buff
->remaining
;
245 SectorMap map
= buff
->bad_sector_map
;
247 buff
->sector_count
= 0;
248 while (buff
->sector_count
< buff
->remaining
&& (map
& 1) == 0) {
249 ++buff
->sector_count
;
253 return buff
->sector_count
;
256 /* if just passed the last segment on a track, wait for BOT
259 int ftape_handle_logical_eot(void)
261 TRACE_FUN(ft_t_flow
);
263 if (ft_runner_status
== logical_eot
) {
266 TRACE(ft_t_noise
, "tape at logical EOT");
267 TRACE_CATCH(ftape_ready_wait(ftape_timeout
.seek
, &status
),);
268 if ((status
& (QIC_STATUS_AT_BOT
| QIC_STATUS_AT_EOT
)) == 0) {
269 TRACE_ABORT(-EIO
, ft_t_err
, "eot/bot not reached");
271 ft_runner_status
= end_of_tape
;
273 if (ft_runner_status
== end_of_tape
) {
274 TRACE(ft_t_noise
, "runner stopped because of logical EOT");
275 ft_runner_status
= idle
;
280 static int check_bot_eot(int status
)
282 TRACE_FUN(ft_t_flow
);
284 if (status
& (QIC_STATUS_AT_BOT
| QIC_STATUS_AT_EOT
)) {
285 ft_location
.bot
= ((ft_location
.track
& 1) == 0 ?
286 (status
& QIC_STATUS_AT_BOT
) != 0:
287 (status
& QIC_STATUS_AT_EOT
) != 0);
288 ft_location
.eot
= !ft_location
.bot
;
289 ft_location
.segment
= (ft_location
.track
+
290 (ft_location
.bot
? 0 : 1)) * ft_segments_per_track
- 1;
291 ft_location
.sector
= -1;
292 ft_location
.known
= 1;
293 TRACE(ft_t_flow
, "tape at logical %s",
294 ft_location
.bot
? "bot" : "eot");
295 TRACE(ft_t_flow
, "segment = %d", ft_location
.segment
);
297 ft_location
.known
= 0;
299 TRACE_EXIT ft_location
.known
;
302 /* Read Id of first sector passing tape head.
304 int ftape_read_id(void)
310 /* Assume tape is running on entry, be able to handle
311 * situation where it stopped or is stopping.
313 ft_location
.known
= 0; /* default is location not known */
315 out
[1] = ft_drive_sel
;
316 TRACE_CATCH(fdc_command(out
, 2),);
317 switch (fdc_interrupt_wait(20 * FT_SECOND
)) {
320 if (ftape_report_drive_status(&status
) >= 0 &&
321 (status
& QIC_STATUS_READY
)) {
322 ftape_tape_running
= 0;
323 TRACE(ft_t_flow
, "tape has stopped");
324 check_bot_eot(status
);
327 ft_location
.known
= 1;
328 ft_location
.segment
= (ftape_segments_per_head
330 + ftape_segments_per_cylinder
333 / FT_SECTORS_PER_SEGMENT
);
334 ft_location
.sector
= ((fdc_sect
- 1)
335 % FT_SECTORS_PER_SEGMENT
);
336 ft_location
.eot
= ft_location
.bot
= 0;
340 /* Didn't find id on tape, must be near end: Wait
343 if (ftape_ready_wait(FT_FOREVER
, &status
) >= 0) {
344 ftape_tape_running
= 0;
345 TRACE(ft_t_flow
, "tape has stopped");
346 check_bot_eot(status
);
350 /* Interrupted or otherwise failing
351 * fdc_interrupt_wait()
353 TRACE(ft_t_err
, "fdc_interrupt_wait failed");
356 if (!ft_location
.known
) {
357 TRACE_ABORT(-EIO
, ft_t_flow
, "no id found");
359 if (ft_location
.sector
== 0) {
360 TRACE(ft_t_flow
, "passing segment %d/%d",
361 ft_location
.segment
, ft_location
.sector
);
363 TRACE(ft_t_fdc_dma
, "passing segment %d/%d",
364 ft_location
.segment
, ft_location
.sector
);
369 static int logical_forward(void)
371 ftape_tape_running
= 1;
372 return ftape_command(QIC_LOGICAL_FORWARD
);
375 int ftape_stop_tape(int *pstatus
)
379 TRACE_FUN(ft_t_flow
);
382 result
= ftape_command_wait(QIC_STOP_TAPE
,
383 ftape_timeout
.stop
, pstatus
);
385 if ((*pstatus
& QIC_STATUS_READY
) == 0) {
388 ftape_tape_running
= 0;
391 } while (result
< 0 && ++retry
<= 3);
393 TRACE(ft_t_err
, "failed ! (fatal)");
398 int ftape_dumb_stop(void)
402 TRACE_FUN(ft_t_flow
);
404 /* Abort current fdc operation if it's busy (probably read
405 * or write operation pending) with a reset.
407 if (fdc_ready_wait(100 /* usec */) < 0) {
408 TRACE(ft_t_noise
, "aborting fdc operation");
411 /* Reading id's after the last segment on a track may fail
412 * but eventually the drive will become ready (logical eot).
414 result
= ftape_report_drive_status(&status
);
415 ft_location
.known
= 0;
417 if (result
== 0 && status
& QIC_STATUS_READY
) {
418 /* Tape is not running any more.
420 TRACE(ft_t_noise
, "tape already halted");
421 check_bot_eot(status
);
422 ftape_tape_running
= 0;
423 } else if (ftape_tape_running
) {
424 /* Tape is (was) still moving.
429 result
= ftape_stop_tape(&status
);
431 /* Tape not yet ready but stopped.
433 result
= ftape_ready_wait(ftape_timeout
.pause
,&status
);
435 } while (ftape_tape_running
436 && !(sigtestsetmask(¤t
->signal
, _NEVER_BLOCK
)));
438 ft_location
.known
= 0;
440 if (ft_runner_status
== aborting
|| ft_runner_status
== do_abort
) {
441 ft_runner_status
= idle
;
446 /* Wait until runner has finished tail buffer.
449 int ftape_wait_segment(buffer_state_enum state
)
453 TRACE_FUN(ft_t_flow
);
455 while (ft_buffer
[ft_tail
]->status
== state
) {
456 TRACE(ft_t_flow
, "state: %d", ft_buffer
[ft_tail
]->status
);
457 /* First buffer still being worked on, wait up to timeout.
459 * Note: we check two times for being killed. 50
460 * seconds are quite long. Note that
461 * fdc_interrupt_wait() is not killable by any
462 * means. ftape_read_segment() wants us to return
463 * -EINTR in case of a signal.
465 FT_SIGNAL_EXIT(_DONT_BLOCK
);
466 result
= fdc_interrupt_wait(50 * FT_SECOND
);
467 FT_SIGNAL_EXIT(_DONT_BLOCK
);
470 ft_t_err
, "fdc_interrupt_wait failed");
472 if (fdc_setup_error
) {
473 /* recover... FIXME */
474 TRACE_ABORT(-EIO
, ft_t_err
, "setup error");
477 if (ft_buffer
[ft_tail
]->status
!= error
) {
480 TRACE_CATCH(ftape_report_drive_status(&status
),);
481 TRACE(ft_t_noise
, "ftape_report_drive_status: 0x%02x", status
);
482 if ((status
& QIC_STATUS_READY
) &&
483 (status
& QIC_STATUS_ERROR
)) {
485 qic117_cmd_t command
;
487 /* Report and clear error state.
488 * In case the drive can't operate at the selected
489 * rate, select the next lower data rate.
491 ftape_report_error(&error
, &command
, 1);
492 if (error
== 31 && command
== QIC_LOGICAL_FORWARD
) {
493 /* drive does not accept this data rate */
494 if (ft_data_rate
> 250) {
496 "Probable data rate conflict");
498 "Lowering data rate to %d Kbps",
500 ftape_half_data_rate();
501 if (ft_buffer
[ft_tail
]->retry
> 0) {
502 /* give it a chance */
503 --ft_buffer
[ft_tail
]->retry
;
506 /* no rate is accepted... */
507 TRACE(ft_t_err
, "We're dead :(");
510 TRACE(ft_t_err
, "Unknown error");
512 TRACE_EXIT
-EIO
; /* g.p. error */
517 /* forward */ static int seek_forward(int segment_id
, int fast
);
519 static int fast_seek(int count
, int reverse
)
523 TRACE_FUN(ft_t_flow
);
526 /* If positioned at begin or end of tape, fast seeking needs
528 * Starting from logical bot needs a (slow) seek to the first
529 * segment before the high speed seek. Most drives do this
530 * automatically but some older don't, so we treat them
532 * Starting from logical eot is even more difficult because
533 * we cannot (slow) reverse seek to the last segment.
536 inhibit_correction
= 0;
537 if (ft_location
.known
&&
538 ((ft_location
.bot
&& !reverse
) ||
539 (ft_location
.eot
&& reverse
))) {
541 /* (slow) skip to first segment on a track
543 seek_forward(ft_location
.track
* ft_segments_per_track
, 0);
546 /* When seeking backwards from
547 * end-of-tape the number of erased
548 * gaps found seems to be higher than
549 * expected. Therefor the drive must
550 * skip some more segments than
551 * calculated, but we don't know how
552 * many. Thus we will prevent the
553 * re-calculation of offset and
554 * overshoot when seeking backwards.
556 inhibit_correction
= 1;
557 count
+= 3; /* best guess */
561 TRACE(ft_t_flow
, "warning: zero or negative count: %d", count
);
565 int nibbles
= count
> 255 ? 3 : 2;
568 TRACE(ft_t_noise
, "skipping clipped at 4095 segment");
571 /* Issue this tape command first. */
573 TRACE(ft_t_noise
, "skipping %d segment(s)", count
);
574 result
= ftape_command(nibbles
== 3 ?
575 QIC_SKIP_EXTENDED_FORWARD
: QIC_SKIP_FORWARD
);
577 TRACE(ft_t_noise
, "backing up %d segment(s)", count
);
578 result
= ftape_command(nibbles
== 3 ?
579 QIC_SKIP_EXTENDED_REVERSE
: QIC_SKIP_REVERSE
);
582 TRACE(ft_t_noise
, "Skip command failed");
584 --count
; /* 0 means one gap etc. */
585 for (i
= 0; i
< nibbles
; ++i
) {
587 result
= ftape_parameter(count
& 15);
591 result
= ftape_ready_wait(ftape_timeout
.rewind
, &status
);
593 ftape_tape_running
= 0;
600 static int validate(int id
)
602 /* Check to see if position found is off-track as reported
603 * once. Because all tracks in one direction lie next to
604 * each other, if off-track the error will be approximately
605 * 2 * ft_segments_per_track.
607 if (ft_location
.track
== -1) {
608 return 1; /* unforseen situation, don't generate error */
610 /* Use margin of ft_segments_per_track on both sides
611 * because ftape needs some margin and the error we're
612 * looking for is much larger !
614 int lo
= (ft_location
.track
- 1) * ft_segments_per_track
;
615 int hi
= (ft_location
.track
+ 2) * ft_segments_per_track
;
617 return (id
>= lo
&& id
< hi
);
621 static int seek_forward(int segment_id
, int fast
)
625 static int margin
= 1; /* fixed: stop this before target */
626 static int overshoot
= 1;
627 static int min_count
= 8;
629 int target
= segment_id
- margin
;
631 int prev_segment
= ft_location
.segment
;
632 TRACE_FUN(ft_t_flow
);
634 if (!ft_location
.known
) {
635 TRACE_ABORT(-EIO
, ft_t_err
,
636 "fatal: cannot seek from unknown location");
638 if (!validate(segment_id
)) {
639 ftape_sleep(1 * FT_SECOND
);
641 TRACE_ABORT(-EIO
, ft_t_err
,
642 "fatal: head off track (bad hardware?)");
644 TRACE(ft_t_noise
, "from %d/%d to %d/0 - %d",
645 ft_location
.segment
, ft_location
.sector
,segment_id
,margin
);
646 count
= target
- ft_location
.segment
- overshoot
;
647 fast_seeking
= (fast
&&
648 count
> (min_count
+ (ft_location
.bot
? 1 : 0)));
650 TRACE(ft_t_noise
, "fast skipping %d segments", count
);
651 expected
= segment_id
- margin
;
654 if (!ftape_tape_running
) {
657 while (ft_location
.segment
< segment_id
) {
658 /* This requires at least one sector in a (bad) segment to
659 * have a valid and readable sector id !
660 * It looks like this is not guaranteed, so we must try
661 * to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!!
663 if (ftape_read_id() < 0 || !ft_location
.known
||
664 sigtestsetmask(¤t
->signal
, _DONT_BLOCK
)) {
665 ft_location
.known
= 0;
666 if (!ftape_tape_running
||
667 ++failures
> FT_SECTORS_PER_SEGMENT
) {
668 TRACE_ABORT(-EIO
, ft_t_err
,
669 "read_id failed completely");
671 FT_SIGNAL_EXIT(_DONT_BLOCK
);
672 TRACE(ft_t_flow
, "read_id failed, retry (%d)",
677 TRACE(ft_t_noise
, "ended at %d/%d (%d,%d)",
678 ft_location
.segment
, ft_location
.sector
,
679 overshoot
, inhibit_correction
);
680 if (!inhibit_correction
&&
681 (ft_location
.segment
< expected
||
682 ft_location
.segment
> expected
+ margin
)) {
683 int error
= ft_location
.segment
- expected
;
685 "adjusting overshoot from %d to %d",
686 overshoot
, overshoot
+ error
);
688 /* All overshoots have the same
689 * direction, so it should never
690 * become negative, but who knows.
692 if (overshoot
< -5 ||
693 overshoot
> OVERSHOOT_LIMIT
) {
695 /* keep sane value */
698 /* keep sane value */
699 overshoot
= OVERSHOOT_LIMIT
;
702 "clipped overshoot to %d",
708 if (ft_location
.known
) {
709 if (ft_location
.segment
> prev_segment
+ 1) {
711 "missed segment %d while skipping",
714 prev_segment
= ft_location
.segment
;
717 if (ft_location
.segment
> segment_id
) {
719 ft_t_noise
, "failed: skip ended at segment %d/%d",
720 ft_location
.segment
, ft_location
.sector
);
725 static int skip_reverse(int segment_id
, int *pstatus
)
728 static int overshoot
= 1;
729 static int min_rewind
= 2; /* 1 + overshoot */
730 static const int margin
= 1; /* stop this before target */
734 int target
= segment_id
- margin
;
735 TRACE_FUN(ft_t_flow
);
737 if (ft_location
.known
&& !validate(segment_id
)) {
738 ftape_sleep(1 * FT_SECOND
);
740 TRACE_ABORT(-EIO
, ft_t_err
,
741 "fatal: head off track (bad hardware?)");
744 if (!ft_location
.known
) {
745 TRACE(ft_t_warn
, "warning: location not known");
747 TRACE(ft_t_noise
, "from %d/%d to %d/0 - %d",
748 ft_location
.segment
, ft_location
.sector
,
750 /* min_rewind == 1 + overshoot_when_doing_minimum_rewind
751 * overshoot == overshoot_when_doing_larger_rewind
752 * Initially min_rewind == 1 + overshoot, optimization
753 * of both values will be done separately.
754 * overshoot and min_rewind can be negative as both are
755 * sums of three components:
756 * any_overshoot == rewind_overshoot -
760 if (ft_location
.segment
- target
- (min_rewind
- 1) < 1) {
763 count
= ft_location
.segment
- target
- overshoot
;
764 short_seek
= (count
< 1);
767 count
= 1; /* do shortest rewind */
768 expected
= ft_location
.segment
- min_rewind
;
769 if (expected
/ft_segments_per_track
!= ft_location
.track
) {
770 expected
= (ft_location
.track
*
771 ft_segments_per_track
);
778 if (ftape_read_id() < 0 || !ft_location
.known
||
779 (sigtestsetmask(¤t
->signal
, _DONT_BLOCK
))) {
780 if ((!ftape_tape_running
&& !ft_location
.known
) ||
781 ++failures
> FT_SECTORS_PER_SEGMENT
) {
782 TRACE_ABORT(-EIO
, ft_t_err
,
783 "read_id failed completely");
785 FT_SIGNAL_EXIT(_DONT_BLOCK
);
786 TRACE_CATCH(ftape_report_drive_status(pstatus
),);
787 TRACE(ft_t_noise
, "ftape_read_id failed, retry (%d)",
791 TRACE(ft_t_noise
, "ended at %d/%d (%d,%d,%d)",
792 ft_location
.segment
, ft_location
.sector
,
793 min_rewind
, overshoot
, inhibit_correction
);
794 if (!inhibit_correction
&&
795 (ft_location
.segment
< expected
||
796 ft_location
.segment
> expected
+ margin
)) {
797 int error
= expected
- ft_location
.segment
;
800 "adjusting min_rewind from %d to %d",
801 min_rewind
, min_rewind
+ error
);
803 if (min_rewind
< -5) {
804 /* is this right ? FIXME ! */
805 /* keep sane value */
808 "clipped min_rewind to %d",
813 "adjusting overshoot from %d to %d",
814 overshoot
, overshoot
+ error
);
816 if (overshoot
< -5 ||
817 overshoot
> OVERSHOOT_LIMIT
) {
819 /* keep sane value */
822 /* keep sane value */
823 overshoot
= OVERSHOOT_LIMIT
;
826 "clipped overshoot to %d",
831 } while (ft_location
.segment
> segment_id
);
832 if (ft_location
.known
) {
833 TRACE(ft_t_noise
, "current location: %d/%d",
834 ft_location
.segment
, ft_location
.sector
);
839 static int determine_position(void)
844 TRACE_FUN(ft_t_flow
);
846 if (!ftape_tape_running
) {
847 /* This should only happen if tape is stopped by isr.
849 TRACE(ft_t_flow
, "waiting for tape stop");
850 if (ftape_ready_wait(ftape_timeout
.pause
, &status
) < 0) {
851 TRACE(ft_t_flow
, "drive still running (fatal)");
852 ftape_tape_running
= 1; /* ? */
855 ftape_report_drive_status(&status
);
857 if (status
& QIC_STATUS_READY
) {
858 /* Drive must be ready to check error state !
860 TRACE(ft_t_flow
, "drive is ready");
861 if (status
& QIC_STATUS_ERROR
) {
863 qic117_cmd_t command
;
865 /* Report and clear error state, try to continue.
867 TRACE(ft_t_flow
, "error status set");
868 ftape_report_error(&error
, &command
, 1);
869 ftape_ready_wait(ftape_timeout
.reset
, &status
);
870 ftape_tape_running
= 0; /* ? */
872 if (check_bot_eot(status
)) {
873 if (ft_location
.bot
) {
874 if ((status
& QIC_STATUS_READY
) == 0) {
875 /* tape moving away from
876 * bot/eot, let's see if we
877 * can catch up with the first
878 * segment on this track.
882 "start tape from logical bot");
883 logical_forward(); /* start moving */
886 if ((status
& QIC_STATUS_READY
) == 0) {
887 TRACE(ft_t_noise
, "waiting for logical end of track");
888 result
= ftape_ready_wait(ftape_timeout
.reset
, &status
);
889 /* error handling needed ? */
892 "tape at logical end of track");
896 TRACE(ft_t_flow
, "start tape");
897 logical_forward(); /* start moving */
898 ft_location
.known
= 0; /* not cleared by logical forward ! */
901 /* tape should be moving now, start reading id's
903 while (!ft_location
.known
&&
904 retry
++ < FT_SECTORS_PER_SEGMENT
&&
905 (result
= ftape_read_id()) < 0) {
907 TRACE(ft_t_flow
, "location unknown");
911 FT_SIGNAL_EXIT(_DONT_BLOCK
);
913 /* read-id somehow failed, tape may
914 * have reached end or some other
917 TRACE(ft_t_flow
, "read-id failed");
918 TRACE_CATCH(ftape_report_drive_status(&status
),);
919 TRACE(ft_t_err
, "ftape_report_drive_status: 0x%02x", status
);
920 if (status
& QIC_STATUS_READY
) {
921 ftape_tape_running
= 0;
922 TRACE(ft_t_noise
, "tape stopped for unknown reason! "
923 "status = 0x%02x", status
);
924 if (status
& QIC_STATUS_ERROR
||
925 !check_bot_eot(status
)) {
926 /* oops, tape stopped but not at end!
933 "tape is positioned at segment %d", ft_location
.segment
);
934 TRACE_EXIT ft_location
.known
? 0 : -EIO
;
937 /* Get the tape running and position it just before the
939 * Seek tape-track and reposition as needed.
941 int ftape_start_tape(int segment_id
, int sector_offset
)
943 int track
= segment_id
/ ft_segments_per_track
;
946 static int last_segment
= -1;
947 static int bad_bus_timing
= 0;
948 /* number of segments passing the head between starting the tape
949 * and being able to access the first sector.
951 static int start_offset
= 1;
953 TRACE_FUN(ft_t_flow
);
955 /* If sector_offset > 0, seek into wanted segment instead of
957 * This allows error recovery if a part of the segment is bad
958 * (erased) causing the tape drive to generate an index pulse
959 * thus causing a no-data error before the requested sector
962 ftape_tape_running
= 0;
963 TRACE(ft_t_noise
, "target segment: %d/%d%s", segment_id
, sector_offset
,
964 ft_buffer
[ft_head
]->retry
> 0 ? " retry" : "");
965 if (ft_buffer
[ft_head
]->retry
> 0) { /* this is a retry */
966 int dist
= segment_id
- last_segment
;
968 if ((int)ft_history
.overrun_errors
< overrun_count_offset
) {
969 overrun_count_offset
= ft_history
.overrun_errors
;
970 } else if (dist
< 0 || dist
> 50) {
971 overrun_count_offset
= ft_history
.overrun_errors
;
972 } else if ((ft_history
.overrun_errors
-
973 overrun_count_offset
) >= 8) {
974 if (ftape_increase_threshold() >= 0) {
975 --ft_buffer
[ft_head
]->retry
;
976 overrun_count_offset
=
977 ft_history
.overrun_errors
;
978 TRACE(ft_t_warn
, "increased threshold because "
979 "of excessive overrun errors");
980 } else if (!bad_bus_timing
&& ft_data_rate
>= 1000) {
981 ftape_half_data_rate();
982 --ft_buffer
[ft_head
]->retry
;
984 overrun_count_offset
=
985 ft_history
.overrun_errors
;
986 TRACE(ft_t_warn
, "reduced datarate because "
987 "of excessive overrun errors");
991 last_segment
= segment_id
;
992 if (ft_location
.track
!= track
||
993 (ftape_might_be_off_track
&& ft_buffer
[ft_head
]->retry
== 0)) {
994 /* current track unknown or not equal to destination
996 ftape_ready_wait(ftape_timeout
.seek
, &status
);
997 ftape_seek_head_to_track(track
);
998 /* overrun_count_offset = ft_history.overrun_errors; */
1002 while (result
< 0 &&
1005 !(sigtestsetmask(¤t
->signal
, _DONT_BLOCK
))) {
1007 if (retry
&& start_offset
< 5) {
1010 /* Check if we are able to catch the requested
1013 if ((ft_location
.known
|| (determine_position() == 0)) &&
1014 ft_location
.segment
>=
1016 ((ftape_tape_running
|| ft_location
.bot
)
1017 ? 0 : start_offset
))) {
1018 /* Too far ahead (in or past target segment).
1020 if (ftape_tape_running
) {
1021 if ((result
= ftape_stop_tape(&status
)) < 0) {
1023 "stop tape failed with code %d",
1027 TRACE(ft_t_noise
, "tape stopped");
1028 ftape_tape_running
= 0;
1030 TRACE(ft_t_noise
, "repositioning");
1031 ++ft_history
.rewinds
;
1032 if (segment_id
% ft_segments_per_track
< start_offset
){
1033 TRACE(ft_t_noise
, "end of track condition\n"
1034 KERN_INFO
"segment_id : %d\n"
1035 KERN_INFO
"ft_segments_per_track: %d\n"
1036 KERN_INFO
"start_offset : %d",
1037 segment_id
, ft_segments_per_track
,
1040 /* If seeking to first segments on
1041 * track better do a complete rewind
1042 * to logical begin of track to get a
1043 * more steady tape motion.
1045 result
= ftape_command_wait(
1046 (ft_location
.track
& 1)
1047 ? QIC_PHYSICAL_FORWARD
1048 : QIC_PHYSICAL_REVERSE
,
1049 ftape_timeout
.rewind
, &status
);
1050 check_bot_eot(status
); /* update location */
1052 result
= skip_reverse(segment_id
- start_offset
,
1056 if (!ft_location
.known
) {
1057 TRACE(ft_t_bug
, "panic: location not known");
1059 continue; /* while() will check for failure */
1061 TRACE(ft_t_noise
, "current segment: %d/%d",
1062 ft_location
.segment
, ft_location
.sector
);
1063 /* We're on the right track somewhere before the
1064 * wanted segment. Start tape movement if needed and
1065 * skip to just before or inside the requested
1066 * segment. Keep tape running.
1069 if (ft_location
.segment
<
1070 (segment_id
- ((ftape_tape_running
|| ft_location
.bot
)
1071 ? 0 : start_offset
))) {
1072 if (sector_offset
> 0) {
1073 result
= seek_forward(segment_id
,
1076 result
= seek_forward(segment_id
- 1,
1081 ft_location
.segment
!=
1082 (segment_id
- (sector_offset
> 0 ? 0 : 1))) {
1087 TRACE(ft_t_err
, "failed to reposition");
1089 ft_runner_status
= running
;