OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [char/] [ftape/] [ftape-rw.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *      Copyright (C) 1993-1995 Bas Laarhoven.
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
 $Source: /home/marcus/revision_ctrl_test/oc_cvs/cvs/or1k/uclinux/uClinux-2.0.x/drivers/char/ftape/ftape-rw.c,v $
19
 $Author: simons $
20
 *
21
 $Revision: 1.1.1.1 $
22
 $Date: 2001-09-10 07:44:17 $
23
 $State: Exp $
24
 *
25
 *      This file contains some common code for the segment read and segment
26
 *      write routines for the QIC-117 floppy-tape driver for Linux.
27
 */
28
 
29
#include <linux/string.h>
30
#include <linux/errno.h>
31
#include <linux/ftape.h>
32
 
33
#include "tracing.h"
34
#include "ftape-rw.h"
35
#include "fdc-io.h"
36
#include "kernel-interface.h"
37
#include "qic117.h"
38
#include "ftape-io.h"
39
#include "ftape-ctl.h"
40
#include "ftape-read.h"
41
#include "ftape-eof.h"
42
#include "ecc.h"
43
#include "ftape-bsm.h"
44
 
45
/*      Global vars.
46
 */
47
volatile enum runner_status_enum runner_status = idle;
48
byte deblock_buffer[(SECTORS_PER_SEGMENT - 3) * SECTOR_SIZE];
49
byte scratch_buffer[(SECTORS_PER_SEGMENT - 3) * SECTOR_SIZE];
50
buffer_struct buffer[NR_BUFFERS];
51
struct wait_queue *wait_intr = NULL;
52
volatile int head;
53
volatile int tail;              /* not volatile but need same type as head */
54
int fdc_setup_error;
55
ftape_last_segment_struct ftape_last_segment;
56
int header_segment_1 = -1;
57
int header_segment_2 = -1;
58
int used_header_segment = -1;
59
location_record location =
60
{-1, 0};
61
volatile int tape_running = 0;
62
format_type format_code;
63
 
64
/*      Local vars.
65
 */
66
static int overrun_count_offset = 0;
67
static int inhibit_correction = 0;
68
 
69
 
70
/*      Increment cyclic buffer nr.
71
 */
72
buffer_struct *
73
 next_buffer(volatile int *x)
74
{
75
        if (++*x >= NR_BUFFERS) {
76
                *x = 0;
77
        }
78
        return &buffer[*x];
79
}
80
 
81
int valid_segment_no(unsigned segment)
82
{
83
        return (segment >= first_data_segment && segment <= ftape_last_segment.id);
84
}
85
 
86
/*      Count nr of 1's in pattern.
87
 */
88
int count_ones(unsigned long mask)
89
{
90
        int bits;
91
 
92
        for (bits = 0; mask != 0; mask >>= 1) {
93
                if (mask & 1) {
94
                        ++bits;
95
                }
96
        }
97
        return bits;
98
}
99
 
100
/*      Calculate Floppy Disk Controller and DMA parameters for a segment.
101
 *      head:   selects buffer struct in array.
102
 *      offset: number of physical sectors to skip (including bad ones).
103
 *      count:  number of physical sectors to handle (including bad ones).
104
 */
105
static int setup_segment(buffer_struct * buff, unsigned int segment_id,
106
        unsigned int sector_offset, unsigned int sector_count, int retry)
107
{
108
        TRACE_FUN(8, "setup_segment");
109
        unsigned long offset_mask;
110
        unsigned long mask;
111
 
112
        buff->segment_id = segment_id;
113
        buff->sector_offset = sector_offset;
114
        buff->remaining = sector_count;
115
        buff->head = segment_id / segments_per_head;
116
        buff->cyl = (segment_id % segments_per_head) / segments_per_cylinder;
117
        buff->sect = (segment_id % segments_per_cylinder) * SECTORS_PER_SEGMENT + 1;
118
        buff->deleted = 0;
119
        offset_mask = (1 << buff->sector_offset) - 1;
120
        mask = get_bad_sector_entry(segment_id) & offset_mask;
121
        while (mask) {
122
                if (mask & 1) {
123
                        offset_mask >>= 1;      /* don't count bad sector */
124
                }
125
                mask >>= 1;
126
        }
127
        buff->data_offset = count_ones(offset_mask);    /* good sectors to skip */
128
        buff->ptr = buff->address + buff->data_offset * SECTOR_SIZE;
129
        TRACEx1(5, "data offset = %d sectors", buff->data_offset);
130
        if (retry) {
131
                buff->soft_error_map &= offset_mask;    /* keep skipped part */
132
        } else {
133
                buff->hard_error_map = buff->soft_error_map = 0;
134
        }
135
        buff->bad_sector_map = get_bad_sector_entry(buff->segment_id);
136
        if (buff->bad_sector_map != 0) {
137
                TRACEx2(4, "segment: %d, bad sector map: %08lx",
138
                        buff->segment_id, buff->bad_sector_map);
139
        } else {
140
                TRACEx1(5, "segment: %d", buff->segment_id);
141
        }
142
        if (buff->sector_offset > 0) {
143
                buff->bad_sector_map >>= buff->sector_offset;
144
        }
145
        if (buff->sector_offset != 0 || buff->remaining != SECTORS_PER_SEGMENT) {
146
                TRACEx2(5, "sector offset = %d, count = %d",
147
                        buff->sector_offset, buff->remaining);
148
        }
149
        /*
150
         *    Segments with 3 or less sectors are not written with
151
         *    valid data because there is no space left for the ecc.
152
         *    The data written is whatever happens to be in the buffer.
153
         *    Reading such a segment will return a zero byte-count.
154
         *    To allow us to read/write segments with all bad sectors
155
         *    we fake one readable sector in the segment. This prevents
156
         *    having to handle these segments in a very special way.
157
         *    It is not important if the reading of this bad sector
158
         *    fails or not (the data is ignored). It is only read to
159
         *    keep the driver running.
160
         *    The QIC-40/80 spec. has no information on how to handle
161
         *    this case, so this is my interpretation.
162
         */
163
        if (buff->bad_sector_map == EMPTY_SEGMENT) {
164
                TRACE(5, "empty segment, fake first sector good");
165
                buff->bad_sector_map = FAKE_SEGMENT;
166
        }
167
        fdc_setup_error = 0;
168
        buff->next_segment = segment_id + 1;
169
        TRACE_EXIT;
170
        return 0;
171
}
172
 
173
/*      Calculate Floppy Disk Controller and DMA parameters for a new segment.
174
 */
175
int setup_new_segment(buffer_struct * buff, unsigned int segment_id, int skip)
176
{
177
        TRACE_FUN(5, "setup_new_segment");
178
        int result = 0;
179
        static int old_segment_id = -1;
180
        static int old_ftape_state = idle;
181
        int retry = 0;
182
        unsigned offset = 0;
183
        int count = SECTORS_PER_SEGMENT;
184
 
185
        TRACEx3(5, "%s segment %d (old = %d)",
186
                (ftape_state == reading) ? "reading" : "writing",
187
                segment_id, old_segment_id);
188
        if (ftape_state != old_ftape_state) {   /* when verifying */
189
                old_segment_id = -1;
190
                old_ftape_state = ftape_state;
191
        }
192
        if (segment_id == old_segment_id) {
193
                ++buff->retry;
194
                ++history.retries;
195
                TRACEx1(5, "setting up for retry nr %d", buff->retry);
196
                retry = 1;
197
                if (skip && buff->skip > 0) {    /* allow skip on retry */
198
                        offset = buff->skip;
199
                        count -= offset;
200
                        TRACEx1(5, "skipping %d sectors", offset);
201
                }
202
        } else {
203
                buff->retry = 0;
204
                buff->skip = 0;
205
                old_segment_id = segment_id;
206
        }
207
        result = setup_segment(buff, segment_id, offset, count, retry);
208
        TRACE_EXIT;
209
        return result;
210
}
211
 
212
/*      Determine size of next cluster of good sectors.
213
 */
214
int calc_next_cluster(buffer_struct * buff)
215
{
216
        /* Skip bad sectors.
217
         */
218
        while (buff->remaining > 0 && (buff->bad_sector_map & 1) != 0) {
219
                buff->bad_sector_map >>= 1;
220
                ++buff->sector_offset;
221
                --buff->remaining;
222
        }
223
        /* Find next cluster of good sectors
224
         */
225
        if (buff->bad_sector_map == 0) { /* speed up */
226
                buff->sector_count = buff->remaining;
227
        } else {
228
                unsigned long map = buff->bad_sector_map;
229
 
230
                buff->sector_count = 0;
231
                while (buff->sector_count < buff->remaining && (map & 1) == 0) {
232
                        ++buff->sector_count;
233
                        map >>= 1;
234
                }
235
        }
236
        return buff->sector_count;
237
}
238
 
239
int check_bot_eot(int status)
240
{
241
        TRACE_FUN(5, "check_bot_eot");
242
 
243
        if (status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) {
244
                location.bot = ((location.track & 1) == 0 ?
245
                                (status & QIC_STATUS_AT_BOT) :
246
                                (status & QIC_STATUS_AT_EOT));
247
                location.eot = !location.bot;
248
                location.segment = (location.track +
249
                        (location.bot ? 0 : 1)) * segments_per_track - 1;
250
                location.sector = -1;
251
                location.known = 1;
252
                TRACEx1(5, "tape at logical %s", location.bot ? "bot" : "eot");
253
                TRACEx1(5, "segment = %d", location.segment);
254
        } else {
255
                location.known = 0;
256
        }
257
        TRACE_EXIT;
258
        return location.known;
259
}
260
 
261
/*      Read Id of first sector passing tape head.
262
 */
263
int ftape_read_id(void)
264
{
265
        TRACE_FUN(8, "ftape_read_id");
266
        int result;
267
        int status;
268
        byte out[2];
269
 
270
        /* Assume tape is running on entry, be able to handle
271
         * situation where it stopped or is stopping.
272
         */
273
        location.known = 0;      /* default is location not known */
274
        out[0] = FDC_READID;
275
        out[1] = FTAPE_UNIT;
276
        result = fdc_command(out, 2);
277
        if (result < 0) {
278
                TRACE(1, "fdc_command failed");
279
        } else {
280
                result = fdc_interrupt_wait(20 * SECOND);
281
                if (result == 0) {
282
                        if (fdc_sect == 0) {
283
                                result = ftape_report_drive_status(&status);
284
                                if (result == 0) {
285
                                        if (status & QIC_STATUS_READY) {
286
                                                tape_running = 0;
287
                                                TRACE(5, "tape has stopped");
288
                                                check_bot_eot(status);
289
                                                if (!location.known) {
290
                                                        result = -EIO;
291
                                                }
292
                                        } else {
293
                                                /*  If read-id failed because of a hard or soft
294
                                                 *  error, return an error. Higher level must retry!
295
                                                 */
296
                                                result = -EIO;
297
                                        }
298
                                }
299
                        } else {
300
                                location.known = 1;
301
                                location.segment = (segments_per_head * fdc_head
302
                                        + segments_per_cylinder * fdc_cyl
303
                                 + (fdc_sect - 1) / SECTORS_PER_SEGMENT);
304
                                location.sector = (fdc_sect - 1) % SECTORS_PER_SEGMENT;
305
                                location.eot =
306
                                    location.bot = 0;
307
                        }
308
                } else if (result == -ETIME) {
309
                        /*  Didn't find id on tape, must be near end: Wait until stopped.
310
                         */
311
                        result = ftape_ready_wait(FOREVER, &status);
312
                        if (result >= 0) {
313
                                tape_running = 0;
314
                                TRACE(5, "tape has stopped");
315
                                check_bot_eot(status);
316
                                if (!location.known) {
317
                                        result = -EIO;
318
                                }
319
                        }
320
                } else {
321
                        /* Interrupted or otherwise failing fdc_interrupt_wait()
322
                         */
323
                        TRACE(1, "fdc_interrupt_wait failed :(");
324
                        result = -EIO;
325
                }
326
        }
327
        if (!location.known) {
328
                TRACE(5, "no id found");
329
        } else {
330
                if (location.sector == 0) {
331
                        TRACEx2(5, "passing segment %d/%d", location.segment, location.sector);
332
                } else {
333
                        TRACEx2(6, "passing segment %d/%d", location.segment, location.sector);
334
                }
335
        }
336
        TRACE_EXIT;
337
        return result;
338
}
339
 
340
static int logical_forward(void)
341
{
342
        tape_running = 1;
343
        return ftape_command(QIC_LOGICAL_FORWARD);
344
}
345
 
346
static int stop_tape(int *pstatus)
347
{
348
        TRACE_FUN(5, "stop_tape");
349
        int retry = 0;
350
        int result;
351
 
352
        do {
353
                result = ftape_command_wait(QIC_STOP_TAPE, timeout.stop, pstatus);
354
                if (result == 0) {
355
                        if ((*pstatus & QIC_STATUS_READY) == 0) {
356
                                result = -EIO;
357
                        } else {
358
                                tape_running = 0;
359
                        }
360
                }
361
        } while (result < 0 && ++retry <= 3);
362
        if (result < 0) {
363
                TRACE(1, "failed ! (fatal)");
364
        }
365
        TRACE_EXIT;
366
        return result;
367
}
368
 
369
int ftape_dumb_stop(void)
370
{
371
        TRACE_FUN(5, "ftape_dumb_stop");
372
        int result;
373
        int status;
374
 
375
        /* Abort current fdc operation if it's busy (probably read
376
         * or write operation pending) with a reset.
377
         */
378
        result = fdc_ready_wait(100 /* usec */ );
379
        if (result < 0) {
380
                TRACE(1, "aborting fdc operation");
381
                fdc_reset();
382
        }
383
        /*  Reading id's after the last segment on a track may fail
384
         *  but eventually the drive will become ready (logical eot).
385
         */
386
        result = ftape_report_drive_status(&status);
387
        location.known = 0;
388
        do {
389
                if (result == 0 && status & QIC_STATUS_READY) {
390
                        /* Tape is not running any more.
391
                         */
392
                        TRACE(5, "tape already halted");
393
                        check_bot_eot(status);
394
                        tape_running = 0;
395
                } else if (tape_running) {
396
                        /* Tape is (was) still moving.
397
                         */
398
#ifdef TESTING
399
                        ftape_read_id();
400
#endif
401
                        result = stop_tape(&status);
402
                } else {
403
                        /* Tape not yet ready but stopped.
404
                         */
405
                        result = ftape_ready_wait(timeout.pause, &status);
406
                }
407
        } while (tape_running);
408
#ifndef TESTING
409
        location.known = 0;
410
#endif
411
        TRACE_EXIT;
412
        return result;
413
}
414
 
415
/*      Wait until runner has finished tail buffer.
416
 */
417
int wait_segment(buffer_state_enum state)
418
{
419
        TRACE_FUN(5, "wait_segment");
420
        int result = 0;
421
 
422
        while (buffer[tail].status == state) {
423
                /*  First buffer still being worked on, wait up to timeout.
424
                 */
425
                result = fdc_interrupt_wait(50 * SECOND);
426
                if (result < 0) {
427
                        if (result != -EINTR) {
428
                                TRACE(1, "fdc_interrupt_wait failed");
429
                                result = -ETIME;
430
                        }
431
                        break;
432
                }
433
                if (fdc_setup_error) {
434
                        TRACE(1, "setup error");
435
                        /* recover... */
436
                        result = -EIO;
437
                        break;
438
                }
439
        }
440
        TRACE_EXIT;
441
        return result;
442
}
443
 
444
/* forward */ static int seek_forward(int segment_id);
445
 
446
int fast_seek(int count, int reverse)
447
{
448
        TRACE_FUN(5, "fast_seek");
449
        int result = 0;
450
        int status;
451
 
452
        if (count > 0) {
453
                /*  If positioned at begin or end of tape, fast seeking needs
454
                 *  special treatment.
455
                 *  Starting from logical bot needs a (slow) seek to the first
456
                 *  segment before the high speed seek. Most drives do this
457
                 *  automatically but some older don't, so we treat them
458
                 *  all the same.
459
                 *  Starting from logical eot is even more difficult because
460
                 *  we cannot (slow) reverse seek to the last segment.
461
                 *  TO BE IMPLEMENTED.
462
                 */
463
                inhibit_correction = 0;
464
                if (location.known &&
465
                    ((location.bot && !reverse) ||
466
                     (location.eot && reverse))) {
467
                        if (!reverse) {
468
                                /*  (slow) skip to first segment on a track
469
                                 */
470
                                seek_forward(location.track * segments_per_track);
471
                                --count;
472
                        } else {
473
                                /*  When seeking backwards from end-of-tape the number
474
                                 *  of erased gaps found seems to be higher than expected.
475
                                 *  Therefor the drive must skip some more segments than
476
                                 *  calculated, but we don't know how many.
477
                                 *  Thus we will prevent the re-calculation of offset
478
                                 *  and overshoot when seeking backwards.
479
                                 */
480
                                inhibit_correction = 1;
481
                                count += 3;     /* best guess */
482
                        }
483
                }
484
        } else {
485
                TRACEx1(5, "warning: zero or negative count: %d", count);
486
        }
487
        if (count > 0) {
488
                int i;
489
                int nibbles = count > 255 ? 3 : 2;
490
 
491
                if (count > 4095) {
492
                        TRACE(4, "skipping clipped at 4095 segment");
493
                        count = 4095;
494
                }
495
                /* Issue this tape command first. */
496
                if (!reverse) {
497
                        TRACEx1(4, "skipping %d segment(s)", count);
498
                        result = ftape_command(nibbles == 3 ?
499
                           QIC_SKIP_EXTENDED_FORWARD : QIC_SKIP_FORWARD);
500
                } else {
501
                        TRACEx1(4, "backing up %d segment(s)", count);
502
                        result = ftape_command(nibbles == 3 ?
503
                           QIC_SKIP_EXTENDED_REVERSE : QIC_SKIP_REVERSE);
504
                }
505
                if (result < 0) {
506
                        TRACE(4, "Skip command failed");
507
                } else {
508
                        --count;        /* 0 means one gap etc. */
509
                        for (i = 0; i < nibbles; ++i) {
510
                                if (result >= 0) {
511
                                        result = ftape_parameter(count & 15);
512
                                        count /= 16;
513
                                }
514
                        }
515
                        result = ftape_ready_wait(timeout.rewind, &status);
516
                        if (result >= 0) {
517
                                tape_running = 0;
518
                        }
519
                }
520
        }
521
        TRACE_EXIT;
522
        return result;
523
}
524
 
525
static int validate(int id)
526
{
527
        /*  Check to see if position found is off-track as reported once.
528
         *  Because all tracks in one direction lie next to each other,
529
         *  if off-track the error will be approximately 2 * segments_per_track.
530
         */
531
        if (location.track == -1) {
532
                return 1;       /* unforeseen situation, don't generate error */
533
        } else {
534
                /*  Use margin of segments_per_track on both sides because ftape
535
                 *  needs some margin and the error we're looking for is much larger !
536
                 */
537
                int lo = (location.track - 1) * segments_per_track;
538
                int hi = (location.track + 2) * segments_per_track;
539
 
540
                return (id >= lo && id < hi);
541
        }
542
}
543
 
544
static int seek_forward(int segment_id)
545
{
546
        TRACE_FUN(5, "seek_forward");
547
        int failures = 0;
548
        int result = 0;
549
        int count;
550
        static int margin = 1;  /* fixed: stop this before target */
551
        static int overshoot = 1;
552
        static int min_count = 8;
553
        int expected = -1;
554
        int target = segment_id - margin;
555
        int fast_seeking;
556
 
557
        if (!location.known) {
558
                TRACE(1, "fatal: cannot seek from unknown location");
559
                result = -EIO;
560
        } else if (!validate(segment_id)) {
561
                TRACE(1, "fatal: head off track (bad hardware?)");
562
                ftape_sleep(1 * SECOND);
563
                ftape_failure = 1;
564
                result = -EIO;
565
        } else {
566
                int prev_segment = location.segment;
567
 
568
                TRACEx4(4, "from %d/%d to %d/0 - %d", location.segment,
569
                        location.sector, segment_id, margin);
570
                count = target - location.segment - overshoot;
571
                fast_seeking = (count > min_count + (location.bot ? 1 : 0));
572
                if (fast_seeking) {
573
                        TRACEx1(5, "fast skipping %d segments", count);
574
                        expected = segment_id - margin;
575
                        fast_seek(count, 0);
576
                }
577
                if (!tape_running) {
578
                        logical_forward();
579
                }
580
                while (location.segment < segment_id) {
581
                        /*  This requires at least one sector in a (bad) segment to
582
                         *  have a valid and readable sector id !
583
                         *  It looks like this is not guaranteed, so we must try
584
                         *  to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!!
585
                         */
586
                        if (ftape_read_id() < 0 || !location.known) {
587
                                location.known = 0;
588
                                if (!tape_running || ++failures > SECTORS_PER_SEGMENT ||
589
                                    (current->signal & _DONT_BLOCK)) {
590
                                        TRACE(1, "read_id failed completely");
591
                                        result = -EIO;
592
                                        break;
593
                                } else {
594
                                        TRACEx1(5, "read_id failed, retry (%d)", failures);
595
                                }
596
                        } else if (fast_seeking) {
597
                                TRACEx4(4, "ended at %d/%d (%d,%d)", location.segment,
598
                                        location.sector, overshoot, inhibit_correction);
599
                                if (!inhibit_correction &&
600
                                    (location.segment < expected ||
601
                                 location.segment > expected + margin)) {
602
                                        int error = location.segment - expected;
603
                                        TRACEx2(4, "adjusting overshoot from %d to %d",
604
                                           overshoot, overshoot + error);
605
                                        overshoot += error;
606
                                        /*  All overshoots have the same direction, so it should
607
                                         *  never become negative, but who knows.
608
                                         */
609
                                        if (overshoot < -5 || overshoot > 10) {
610
                                                if (overshoot < 0) {
611
                                                        overshoot = -5;         /* keep sane value */
612
                                                } else {
613
                                                        overshoot = 10;         /* keep sane value */
614
                                                }
615
                                                TRACEx1(4, "clipped overshoot to %d", overshoot);
616
                                        }
617
                                }
618
                                fast_seeking = 0;
619
                        }
620
                        if (location.known) {
621
                                if (location.segment > prev_segment + 1) {
622
                                        TRACEx1(4, "missed segment %d while skipping", prev_segment + 1);
623
                                }
624
                                prev_segment = location.segment;
625
                        }
626
                }
627
                if (location.segment > segment_id) {
628
                        TRACEx2(4, "failed: skip ended at segment %d/%d",
629
                                location.segment, location.sector);
630
                        result = -EIO;
631
                }
632
        }
633
        TRACE_EXIT;
634
        return result;
635
}
636
 
637
static int skip_reverse(int segment_id, int *pstatus)
638
{
639
        TRACE_FUN(5, "skip_reverse");
640
        int result = 0;
641
        int failures = 0;
642
        static int overshoot = 1;
643
        static int min_rewind = 2;      /* 1 + overshoot */
644
        static const int margin = 1;    /* stop this before target */
645
        int expected = 0;
646
        int count;
647
        int short_seek;
648
        int target = segment_id - margin;
649
 
650
        if (location.known && !validate(segment_id)) {
651
                TRACE(1, "fatal: head off track (bad hardware?)");
652
                ftape_sleep(1 * SECOND);
653
                ftape_failure = 1;
654
                result = -EIO;
655
        } else
656
                do {
657
                        if (!location.known) {
658
                                TRACE(-1, "warning: location not known");
659
                        }
660
                        TRACEx4(4, "from %d/%d to %d/0 - %d",
661
                                location.segment, location.sector, segment_id, margin);
662
                        /*  min_rewind == 1 + overshoot_when_doing_minimum_rewind
663
                         *  overshoot  == overshoot_when_doing_larger_rewind
664
                         *  Initially min_rewind == 1 + overshoot, optimization
665
                         *  of both values will be done separately.
666
                         *  overshoot and min_rewind can be negative as both are
667
                         *  sums of three components:
668
                         *  any_overshoot == rewind_overshoot - stop_overshoot - start_overshoot
669
                         */
670
                        if (location.segment - target - (min_rewind - 1) < 1) {
671
                                short_seek = 1;
672
                        } else {
673
                                count = location.segment - target - overshoot;
674
                                short_seek = (count < 1);
675
                        }
676
                        if (short_seek) {
677
                                count = 1;      /* do shortest rewind */
678
                                expected = location.segment - min_rewind;
679
                                if (expected / segments_per_track != location.track) {
680
                                        expected = location.track * segments_per_track;
681
                                }
682
                        } else {
683
                                expected = target;
684
                        }
685
                        fast_seek(count, 1);
686
                        logical_forward();
687
                        result = ftape_read_id();
688
                        if (result == 0 && location.known) {
689
                                TRACEx5(4, "ended at %d/%d (%d,%d,%d)", location.segment,
690
                                        location.sector, min_rewind, overshoot, inhibit_correction);
691
                                if (!inhibit_correction &&
692
                                    (location.segment < expected ||
693
                                 location.segment > expected + margin)) {
694
                                        int error = expected - location.segment;
695
                                        if (short_seek) {
696
                                                TRACEx2(4, "adjusting min_rewind from %d to %d",
697
                                                        min_rewind, min_rewind + error);
698
                                                min_rewind += error;
699
                                                if (min_rewind < -5) {  /* is this right ? FIXME ! */
700
                                                        min_rewind = -5;        /* keep sane value */
701
                                                        TRACEx1(4, "clipped min_rewind to %d", min_rewind);
702
                                                }
703
                                        } else {
704
                                                TRACEx2(4, "adjusting overshoot from %d to %d",
705
                                                        overshoot, overshoot + error);
706
                                                overshoot += error;
707
                                                if (overshoot < -5 || overshoot > 10) {
708
                                                        if (overshoot < 0) {
709
                                                                overshoot = -5;         /* keep sane value */
710
                                                        } else {
711
                                                                overshoot = 10;         /* keep sane value */
712
                                                        }
713
                                                        TRACEx1(4, "clipped overshoot to %d", overshoot);
714
                                                }
715
                                        }
716
                                }
717
                        } else {
718
                                if ((!tape_running && !location.known) ||
719
                                    ++failures > SECTORS_PER_SEGMENT) {
720
                                        TRACE(1, "read_id failed completely");
721
                                        result = -EIO;
722
                                        break;
723
                                } else {
724
                                        TRACEx1(5, "ftape_read_id failed, retry (%d)", failures);
725
                                }
726
                                result = ftape_report_drive_status(pstatus);
727
                                if (result < 0) {
728
                                        TRACEi(1, "ftape_report_drive_status failed with code", result);
729
                                        break;
730
                                }
731
                        }
732
                } while (location.segment > segment_id &&
733
                         (current->signal & _DONT_BLOCK) == 0);
734
        if (location.known) {
735
                TRACEx2(4, "current location: %d/%d", location.segment, location.sector);
736
        }
737
        TRACE_EXIT;
738
        return result;
739
}
740
 
741
static int determine_position(void)
742
{
743
        TRACE_FUN(5, "determine_position");
744
        int retry = 0;
745
        int fatal = 0;
746
        int status;
747
        int result;
748
 
749
        if (!tape_running) {
750
                /*  This should only happen if tape is stopped by isr.
751
                 */
752
                TRACE(5, "waiting for tape stop");
753
                result = ftape_ready_wait(timeout.pause, &status);
754
                if (result < 0) {
755
                        TRACE(5, "drive still running (fatal)");
756
                        tape_running = 1;       /* ? */
757
                }
758
        } else {
759
                ftape_report_drive_status(&status);
760
        }
761
        if (status & QIC_STATUS_READY) {
762
                /*  Drive must be ready to check error state !
763
                 */
764
                TRACE(5, "drive is ready");
765
                if (status & QIC_STATUS_ERROR) {
766
                        int error;
767
                        int command;
768
 
769
                        /*  Report and clear error state, try to continue.
770
                         */
771
                        TRACE(5, "error status set");
772
                        ftape_report_error(&error, &command, 1);
773
                        ftape_ready_wait(timeout.reset, &status);
774
                        tape_running = 0;        /* ? */
775
                }
776
                if (check_bot_eot(status)) {
777
                        if (location.bot) {
778
                                if ((status & QIC_STATUS_READY) == 0) {
779
                                        /* tape moving away from bot/eot, let's see if we
780
                                         * can catch up with the first segment on this track.
781
                                         */
782
                                } else {
783
                                        TRACE(5, "start tape from logical bot");
784
                                        logical_forward();      /* start moving */
785
                                }
786
                        } else {
787
                                if ((status & QIC_STATUS_READY) == 0) {
788
                                        TRACE(4, "waiting for logical end of track");
789
                                        result = ftape_ready_wait(timeout.reset, &status);
790
                                        /* error handling needed ? */
791
                                } else {
792
                                        TRACE(4, "tape at logical end of track");
793
                                }
794
                        }
795
                } else {
796
                        TRACE(5, "start tape");
797
                        logical_forward();      /* start moving */
798
                        location.known = 0;      /* not cleared by logical forward ! */
799
                }
800
        }
801
        if (!location.known) {
802
                /* tape should be moving now, start reading id's
803
                 */
804
                TRACE(5, "location unknown");
805
                do {
806
                        result = ftape_read_id();
807
                        if (result < 0) {
808
                                /*  read-id somehow failed, tape may have reached end
809
                                 *  or some other error happened.
810
                                 */
811
                                TRACE(5, "read-id failed");
812
                                ftape_report_drive_status(&status);
813
                                if (status & QIC_STATUS_READY) {
814
                                        tape_running = 0;
815
                                        TRACEx1(4, "tape stopped for unknown reason ! status = 0x%02x",
816
                                                status);
817
                                        if (status & QIC_STATUS_ERROR) {
818
                                                fatal = 1;
819
                                        } else {
820
                                                if (check_bot_eot(status)) {
821
                                                        result = 0;
822
                                                } else {
823
                                                        fatal = 1;      /* oops, tape stopped but not at end ! */
824
                                                }
825
                                        }
826
                                }
827
                                result = -EIO;
828
                        }
829
                } while (result < 0 && !fatal && ++retry < SECTORS_PER_SEGMENT);
830
        } else {
831
                result = 0;
832
        }
833
        TRACEx1(5, "tape is positioned at segment %d", location.segment);
834
        TRACE_EXIT;
835
        return result;
836
}
837
 
838
/*      Get the tape running and position it just before the
839
 *      requested segment.
840
 *      Seek tape-track and reposition as needed.
841
 */
842
int ftape_start_tape(int segment_id, int sector_offset)
843
{
844
        TRACE_FUN(5, "ftape_start_tape");
845
        int track = segment_id / segments_per_track;
846
        int result = -EIO;
847
        int status;
848
        static int last_segment = -1;
849
        static int bad_bus_timing = 0;
850
        /* number of segments passing the head between starting the tape
851
         * and being able to access the first sector.
852
         */
853
        static int start_offset = 1;
854
        int retry = 0;
855
 
856
        /* If sector_offset > 0, seek into wanted segment instead of
857
         * into previous.
858
         * This allows error recovery if a part of the segment is bad
859
         * (erased) causing the tape drive to generate an index pulse
860
         * thus causing a no-data error before the requested sector
861
         * is reached.
862
         */
863
        tape_running = 0;
864
        TRACEx3(4, "target segment: %d/%d%s", segment_id, sector_offset,
865
                buffer[head].retry > 0 ? " retry" : "");
866
        if (buffer[head].retry > 0) {    /* this is a retry */
867
                if (!bad_bus_timing && ftape_data_rate == 1 &&
868
                    history.overrun_errors - overrun_count_offset >= 8) {
869
                        ftape_set_data_rate(ftape_data_rate + 1);
870
                        bad_bus_timing = 1;
871
                        TRACE(2, "reduced datarate because of excessive overrun errors");
872
                }
873
        }
874
        last_segment = segment_id;
875
        if (location.track != track || (might_be_off_track &&
876
                                        buffer[head].retry == 0)) {
877
                /* current track unknown or not equal to destination
878
                 */
879
                ftape_ready_wait(timeout.seek, &status);
880
                ftape_seek_head_to_track(track);
881
                overrun_count_offset = history.overrun_errors;
882
        }
883
        do {
884
                if (!location.known) {
885
                        determine_position();
886
                }
887
                /*  Check if we are able to catch the requested segment in time.
888
                 */
889
                if (location.known && location.segment >= segment_id -
890
                    ((tape_running || location.bot) ? 0 : start_offset)) {
891
                        /*  Too far ahead (in or past target segment).
892
                         */
893
                        if (tape_running) {
894
                                result = stop_tape(&status);
895
                                if (result < 0) {
896
                                        TRACEi(1, "stop tape failed with code", result);
897
                                        break;
898
                                }
899
                                TRACE(5, "tape stopped");
900
                                tape_running = 0;
901
                        }
902
                        TRACE(5, "repositioning");
903
                        ++history.rewinds;
904
                        if (segment_id % segments_per_track < start_offset) {
905
                                /*  If seeking to first segments on track better do a complete
906
                                 *  rewind to logical begin of track to get a more steady tape
907
                                 *  motion.
908
                                 */
909
                                result = ftape_command_wait((location.track & 1) ?
910
                                                   QIC_PHYSICAL_FORWARD :
911
                                                    QIC_PHYSICAL_REVERSE,
912
                                                timeout.rewind, &status);
913
                                check_bot_eot(status);  /* update location */
914
                        } else {
915
                                result = skip_reverse(segment_id - start_offset, &status);
916
                        }
917
                }
918
                if (!location.known) {
919
                        TRACE(-1, "panic: location not known");
920
                        result = -EIO;
921
                        if ((current->signal & _DONT_BLOCK) || ftape_failure) {
922
                                break;
923
                        } else {
924
                                continue;
925
                        }
926
                }
927
                TRACEx2(4, "current segment: %d/%d", location.segment, location.sector);
928
                /*  We're on the right track somewhere before the wanted segment.
929
                 *  Start tape movement if needed and skip to just before or inside
930
                 *  the requested segment. Keep tape running.
931
                 */
932
                result = 0;
933
                if (location.segment < segment_id -
934
                    ((tape_running || location.bot) ? 0 : start_offset)) {
935
                        if (sector_offset > 0) {
936
                                result = seek_forward(segment_id);
937
                        } else {
938
                                result = seek_forward(segment_id - 1);
939
                        }
940
                }
941
                if (result == 0 &&
942
                    location.segment != segment_id - (sector_offset > 0 ? 0 : 1)) {
943
                        result = -EIO;
944
                }
945
        } while (result < 0 && !ftape_failure &&
946
                 (current->signal & _DONT_BLOCK) == 0 &&
947
                 ++retry <= 5);
948
        if (result < 0) {
949
                TRACE(1, "failed to reposition");
950
        }
951
        TRACE_EXIT;
952
        return result;
953
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.