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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [char/] [ftape/] [fdc-isr.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/*
2
 *      Copyright (C) 1994-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/rc203soc/sw/uClinux/drivers/char/ftape/fdc-isr.c,v $
19
 $Author: jcastillo $
20
 *
21
 $Revision: 1.1 $
22
 $Date: 2005-12-20 10:16:52 $
23
 $State: Exp $
24
 *
25
 *      This file contains the interrupt service routine and associated
26
 *      code for the QIC-40/80 tape streamer device driver.
27
 */
28
 
29
#include <linux/ftape.h>
30
#include <asm/io.h>
31
#include <asm/dma.h>
32
 
33
#define volatile                /* */
34
 
35
#include "tracing.h"
36
#include "fdc-isr.h"
37
#include "qic117.h"
38
#include "fdc-io.h"
39
#include "ftape-ctl.h"
40
#include "ftape-rw.h"
41
#include "ftape-io.h"
42
#include "calibr.h"
43
#include "ftape-bsm.h"
44
 
45
/*      Global vars.
46
 */
47
volatile int expected_stray_interrupts = 0;
48
volatile int seek_completed = 0;
49
volatile int interrupt_seen = 0;
50
volatile int expect_stray_interrupt = 0;
51
int random_rw = 0;
52
 
53
/*      Local vars.
54
 */
55
typedef enum {
56
        no_error = 0, id_am_error = 0x01, id_crc_error = 0x02,
57
        data_am_error = 0x04, data_crc_error = 0x08,
58
        no_data_error = 0x10, overrun_error = 0x20,
59
} error_cause;
60
static int hide_interrupt;
61
static int stop_read_ahead = 0;
62
 
63
 
64
static void print_error_cause(int cause)
65
{
66
        TRACE_FUN(8, "print_error_cause");
67
 
68
        switch (cause) {
69
        case no_data_error:
70
                TRACE(4, "no data error");
71
                break;
72
        case id_am_error:
73
                TRACE(4, "id am error");
74
                break;
75
        case id_crc_error:
76
                TRACE(4, "id crc error");
77
                break;
78
        case data_am_error:
79
                TRACE(4, "data am error");
80
                break;
81
        case data_crc_error:
82
                TRACE(4, "data crc error");
83
                break;
84
        case overrun_error:
85
                TRACE(4, "overrun error");
86
                break;
87
        default:
88
        }
89
        TRACE_EXIT;
90
}
91
 
92
static char *
93
get_fdc_mode_text(fdc_mode_enum fdc_mode)
94
{
95
        switch (fdc_mode) {
96
        case fdc_idle:
97
                return "fdc_idle";
98
        case fdc_reading_data:
99
                return "fdc_reading_data";
100
        case fdc_seeking:
101
                return "fdc_seeking";
102
        case fdc_writing_data:
103
                return "fdc_writing_data";
104
        case fdc_reading_id:
105
                return "fdc_reading_id";
106
        case fdc_recalibrating:
107
                return "fdc_recalibrating";
108
        default:
109
                return "unknown";
110
        }
111
}
112
 
113
static void
114
decode_irq_cause(fdc_mode_enum fdc_mode, byte st[],
115
                 char **fdc_mode_txt, error_cause * cause)
116
{
117
        TRACE_FUN(8, "decode_irq_cause");
118
 
119
        /*  Valid st[], decode cause of interrupt.
120
         */
121
        *fdc_mode_txt = get_fdc_mode_text(fdc_mode);
122
        switch (st[0] & ST0_INT_MASK) {
123
        case FDC_INT_NORMAL:
124
                TRACEx1(fdc_mode == fdc_reading_id ? 6 : 5,
125
                        "normal completion: %s", *fdc_mode_txt);
126
                *cause = no_error;
127
                break;
128
        case FDC_INT_ABNORMAL:
129
                TRACEx1(5, "abnormal completion %s", *fdc_mode_txt);
130
                TRACEx3(6, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x",
131
                        st[0], st[1], st[2]);
132
                TRACEx4(6, "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x",
133
                        st[3], st[4], st[5], st[6]);
134
                if (st[1] & 0x01) {
135
                        if (st[2] & 0x01) {
136
                                *cause = data_am_error;
137
                        } else {
138
                                *cause = id_am_error;
139
                        }
140
                } else if (st[1] & 0x20) {
141
                        if (st[2] & 0x20) {
142
                                *cause = data_crc_error;
143
                        } else {
144
                                *cause = id_crc_error;
145
                        }
146
                } else if (st[1] & 0x04) {
147
                        *cause = no_data_error;
148
                } else if (st[1] & 0x10) {
149
                        *cause = overrun_error;
150
                }
151
                print_error_cause(*cause);
152
                break;
153
        case FDC_INT_INVALID:
154
                TRACEx1(5, "invalid completion %s", *fdc_mode_txt);
155
                *cause = no_error;
156
                break;
157
        case FDC_INT_READYCH:
158
                TRACEx1(5, "ready change %s", *fdc_mode_txt);
159
                *cause = no_error;
160
                break;
161
        default:
162
        }
163
        TRACE_EXIT;
164
}
165
 
166
static void update_history(error_cause cause)
167
{
168
        switch (cause) {
169
        case id_am_error:
170
                history.id_am_errors++;
171
                break;
172
        case id_crc_error:
173
                history.id_crc_errors++;
174
                break;
175
        case data_am_error:
176
                history.data_am_errors++;
177
                break;
178
        case data_crc_error:
179
                history.data_crc_errors++;
180
                break;
181
        case overrun_error:
182
                history.overrun_errors++;
183
                break;
184
        case no_data_error:
185
                history.no_data_errors++;
186
                break;
187
        default:
188
        }
189
}
190
 
191
static void skip_bad_sector(buffer_struct * buff)
192
{
193
        TRACE_FUN(8, "skip_bad_sector");
194
 
195
        /* Mark sector as soft error and skip it
196
         */
197
        if (buff->remaining > 0) {
198
                ++buff->sector_offset;
199
                ++buff->data_offset;
200
                --buff->remaining;
201
                buff->ptr += SECTOR_SIZE;
202
                buff->bad_sector_map >>= 1;
203
        } else {
204
                ++buff->sector_offset;  /* hack for error maps */
205
                TRACE(1, "skipping last sector in segment");
206
        }
207
        TRACE_EXIT;
208
}
209
 
210
static void update_error_maps(buffer_struct * buff, unsigned error_offset)
211
{
212
        TRACE_FUN(8, "update_error_maps");
213
        int hard = 0;
214
 
215
        /* error_offset is a sector offset !
216
         */
217
        if (buff->retry < SOFT_RETRIES) {
218
                buff->soft_error_map |= (1 << error_offset);
219
        } else {
220
                buff->hard_error_map |= (1 << error_offset);
221
                buff->soft_error_map &= ~buff->hard_error_map;
222
                buff->retry = -1;       /* will be set to 0 in setup_segment */
223
                hard = 1;
224
        }
225
        TRACEx2(4, "sector %d : %s error", SECTOR(error_offset),
226
                hard ? "hard" : "soft");
227
        TRACEx2(5, "hard map: 0x%08lx, soft map: 0x%08lx",
228
                buff->hard_error_map, buff->soft_error_map);
229
        TRACE_EXIT;
230
}
231
 
232
/*
233
 *  Error cause:   Amount xferred:  Action:
234
 *
235
 *  id_am_error         0           mark bad and skip
236
 *  id_crc_error        0           mark bad and skip
237
 *  data_am_error       0           mark bad and skip
238
 *  data_crc_error    % 1024        mark bad and skip
239
 *  no_data_error       0           retry on write
240
 *                                  mark bad and skip on read
241
 *  overrun_error  [ 0..all-1 ]     mark bad and skip
242
 *  no_error           all          continue
243
 */
244
static void determine_progress(buffer_struct * buff, error_cause cause, int mode)
245
{
246
        TRACE_FUN(8, "determine_progress");
247
        unsigned nr_not_xferred;
248
        unsigned nr_xferred;
249
        unsigned dma_residue;
250
 
251
        /*  Using less preferred order of disable_dma and get_dma_residue
252
         *  because this seems to fail on at least one system if reversed!
253
         */
254
        dma_residue = get_dma_residue(fdc.dma);
255
        disable_dma(fdc.dma);
256
        nr_xferred = buff->sector_count * SECTOR_SIZE - dma_residue;
257
        if (cause == no_error && dma_residue == 0) {
258
                nr_not_xferred = 0;
259
        } else {
260
                if (cause == no_error) {
261
                        TRACEx1(4, "unexpected DMA residue: 0x%04x", dma_residue);
262
                } else {
263
                        TRACEx1(6, "DMA residue = 0x%04x", dma_residue);
264
                }
265
                nr_not_xferred = ((dma_residue + (SECTOR_SIZE - 1)) / SECTOR_SIZE);
266
                buff->sector_count -= nr_not_xferred;   /* adjust to actual value */
267
        }
268
        /*  Update var's influenced by the DMA operation.
269
         */
270
        if (buff->sector_count > 0) {
271
                buff->sector_offset += buff->sector_count;
272
                buff->data_offset += buff->sector_count;
273
                buff->ptr += buff->sector_count * SECTOR_SIZE;
274
                buff->remaining -= buff->sector_count;
275
                buff->bad_sector_map >>= buff->sector_count;
276
        }
277
        if (cause == no_error) {
278
                TRACEx1(5, "%d Sector(s) transferred", buff->sector_count);
279
        } else if (cause == no_data_error) {
280
                TRACEx1(5, "Sector %d not found", SECTOR(buff->sector_offset));
281
        } else if (nr_xferred > 0 || cause == id_crc_error ||
282
                   cause == id_am_error || cause == data_am_error) {
283
                TRACEx1(5, "Error in sector %d", SECTOR(buff->sector_offset));
284
        } else if (cause == overrun_error) {
285
                /* got an overrun error on the first byte, must be a hardware problem
286
                 */
287
                TRACE(-1, "Unexpected error: failing DMA controller ?");
288
        } else {
289
                TRACEx1(4, "Unexpected error at sector %d", SECTOR(buff->sector_offset));
290
        }
291
        /*  Sector_offset points to the problem area, except if we got
292
         *  a data_crc_error. In that case it points one past the failing
293
         *  sector.
294
         *  Now adjust sector_offset so it always points one past he
295
         *  failing sector. I.e. skip the bad sector.
296
         */
297
        if (cause != no_error) {
298
                if (cause != data_crc_error) {
299
                        skip_bad_sector(buff);
300
                }
301
                update_error_maps(buff, buff->sector_offset - 1);
302
        }
303
        TRACE_EXIT;
304
}
305
 
306
static int calc_steps(int cmd)
307
{
308
        if (current_cylinder > cmd) {
309
                return current_cylinder - cmd;
310
        } else {
311
                return current_cylinder + cmd;
312
        }
313
}
314
 
315
static void pause_tape(unsigned segment, int retry, int fdc_mode)
316
{
317
        TRACE_FUN(8, "pause_tape");
318
        int result;
319
        /*  The 3rd initializer needs to be explicit or else gcc will
320
         *  generate a reference to memset :-(
321
         */
322
        byte out[3] =
323
        {FDC_SEEK, FTAPE_UNIT, 0};
324
 
325
        /*  We'll use a raw seek command to get the tape to rewind
326
         *  and stop for a retry.
327
         */
328
        ++history.rewinds;
329
        if (qic117_cmds[current_command].non_intr) {
330
                TRACE(2, "motion command may be issued too soon");
331
        }
332
        if (retry && (fdc_mode == fdc_reading_data || fdc_mode == fdc_reading_id)) {
333
                current_command = QIC_MICRO_STEP_PAUSE;
334
                might_be_off_track = 1;
335
        } else {
336
                current_command = QIC_PAUSE;
337
        }
338
        out[2] = calc_steps(current_command);
339
        result = fdc_command(out, 3);   /* issue QIC_117 command */
340
        if (result < 0) {
341
                TRACEx1(4, "qic-pause failed, status = %d", result);
342
        } else {
343
                location.known = 0;
344
                runner_status = idle;
345
                hide_interrupt = 1;
346
                tape_running = 0;
347
        }
348
        TRACE_EXIT;
349
}
350
 
351
static void stop_tape(unsigned segment)
352
{
353
        TRACE_FUN(8, "stop_tape");
354
        int result;
355
        byte out[3] =
356
        {FDC_SEEK, FTAPE_UNIT, calc_steps(QIC_STOP_TAPE)};
357
 
358
        if (qic117_cmds[current_command].non_intr) {
359
                TRACE(2, "motion command may be issued too soon");
360
        }
361
        current_command = QIC_STOP_TAPE;
362
        /*  We'll use a raw seek command to get the tape to stop
363
         */
364
        result = fdc_command(out, 3);   /* issue QIC_117 command */
365
        if (result < 0) {
366
                TRACEx1(4, "qic-stop failed, status = %d", result);
367
        } else {
368
                runner_status = idle;
369
                hide_interrupt = 1;
370
                tape_running = 0;
371
        }
372
        TRACE_EXIT;
373
}
374
 
375
static void continue_xfer(buffer_struct ** p_buff, error_cause cause,
376
                          int fdc_mode, unsigned skip)
377
{
378
        TRACE_FUN(8, "continue_xfer");
379
        buffer_struct *buff = *p_buff;
380
        int write = (fdc_mode == fdc_writing_data);
381
        byte fdc_op = (write) ? FDC_WRITE : FDC_READ;
382
 
383
        if (skip > 0) {
384
                /* This part can be removed if it never happens
385
                 */
386
                if (runner_status != running ||
387
                    (buff->status != (write ? writing : reading))) {
388
                        TRACEx2(1, "unexpected runner/buffer state %d/%d",
389
                                runner_status, buff->status);
390
                        buff->status = error;
391
                        *p_buff = next_buffer(&head);   /* finish this buffer */
392
                        runner_status = aborting;
393
                        fdc_mode = fdc_idle;
394
                }
395
        }
396
        if (buff->remaining > 0 && calc_next_cluster(&buffer[head]) > 0) {
397
                /* still sectors left in current segment, continue with this segment
398
                 */
399
                if (setup_fdc_and_dma(&buffer[head], fdc_op) < 0) {
400
                        /* failed, abort operation
401
                         */
402
                        buff->bytes = buff->ptr - buff->address;
403
                        buff->status = error;
404
                        buff = *p_buff = next_buffer(&head);    /* finish this buffer */
405
                        runner_status = aborting;
406
                        fdc_mode = fdc_idle;
407
                }
408
        } else {
409
                /* current segment completed
410
                 */
411
                unsigned last_segment = buff->segment_id;
412
                int eot = ((last_segment + 1) % segments_per_track) == 0;
413
                int next = buff->next_segment;  /* 0 means stop ! */
414
 
415
                buff->bytes = buff->ptr - buff->address;
416
                buff->status = done;
417
                buff = *p_buff = next_buffer(&head);
418
                if (eot) {
419
                        /* finished last segment on current track, can't continue
420
                         */
421
                        runner_status = logical_eot;
422
                        fdc_mode = fdc_idle;
423
                } else if (next > 0) {
424
                        /* continue with next segment
425
                         */
426
                        if (buff->status == waiting) {
427
                                if (write && next != buff->segment_id) {
428
                                        TRACE(5, "segments out of order, aborting write");
429
                                        runner_status = do_abort;
430
                                        fdc_mode = fdc_idle;
431
                                } else {
432
                                        setup_new_segment(&buffer[head], next, 0);
433
                                        if (stop_read_ahead) {
434
                                                buff->next_segment = 0;
435
                                                stop_read_ahead = 0;
436
                                        }
437
                                        if (calc_next_cluster(&buffer[head]) == 0 ||
438
                                            setup_fdc_and_dma(&buffer[head], fdc_op) != 0) {
439
                                                TRACEx1(1, "couldn't start %s-ahead", (write) ? "write" : "read");
440
                                                runner_status = do_abort;
441
                                                fdc_mode = fdc_idle;
442
                                        } else {
443
                                                buff->status = (write) ? writing : reading;     /* keep on going */
444
                                        }
445
                                }
446
                        } else {
447
                                TRACEx1(5, "all input buffers %s, pausing tape",
448
                                        (write) ? "empty" : "full");
449
                                pause_tape(last_segment, 0, fdc_mode);
450
                                runner_status = idle;   /* not quite true until next irq */
451
                        }
452
                } else {
453
                        /* don't continue with next segment
454
                         */
455
                        TRACEx1(5, "no %s allowed, stopping tape",
456
                                (write) ? "write next" : "read ahead");
457
                        if (random_rw) {
458
                                stop_tape(last_segment);
459
                        } else {
460
                                pause_tape(last_segment, 0, fdc_mode);
461
                        }
462
                        runner_status = idle;   /* not quite true until next irq */
463
                }
464
        }
465
        TRACE_EXIT;
466
        return;
467
}
468
 
469
static void
470
retry_sector(buffer_struct ** p_buff, error_cause cause, int fdc_mode,
471
             unsigned skip)
472
{
473
        TRACE_FUN(8, "retry_sector");
474
        buffer_struct *buff = *p_buff;
475
 
476
        TRACEx1(4, "%s error, will retry",
477
                (fdc_mode == fdc_writing_data) ? "write" : "read");
478
        pause_tape(buff->segment_id, 1, fdc_mode);
479
        runner_status = aborting;
480
        buff->status = error;
481
        buff->skip = skip;
482
        TRACE_EXIT;
483
}
484
 
485
static unsigned
486
find_resume_point(buffer_struct * buff)
487
{
488
        TRACE_FUN(8, "find_resume_point");
489
        int i = 0;
490
        unsigned long mask;
491
        unsigned long map;
492
 
493
        /*  This function is to be called after all variables have been
494
         *  updated to point past the failing sector.
495
         *  If there are any soft errors before the failing sector,
496
         *  find the first soft error and return the sector offset.
497
         *  Otherwise find the last hard error.
498
         *  Note: there should always be at least one hard or soft error !
499
         */
500
        if (buff->sector_offset < 1 || buff->sector_offset > 32) {
501
                TRACEx1(1, "bug: sector_offset = %d", buff->sector_offset);
502
        } else {
503
                if (buff->sector_offset >= 32) {        /* C-limitation on shift ! */
504
                        mask = 0xffffffff;
505
                } else {
506
                        mask = (1 << buff->sector_offset) - 1;
507
                }
508
                map = buff->soft_error_map & mask;
509
                if (map) {
510
                        while ((map & (1 << i)) == 0) {
511
                                ++i;
512
                        }
513
                        TRACEx1(4, "at sector %d", SECTOR(i));
514
                } else {
515
                        map = buff->hard_error_map & mask;
516
                        i = buff->sector_offset - 1;
517
                        if (map) {
518
                                while ((map & (1 << i)) == 0) {
519
                                        --i;
520
                                }
521
                                TRACEx1(4, "after sector %d", SECTOR(i));
522
                                ++i;    /* first sector after last hard error */
523
                        } else {
524
                                TRACE(1, "bug: no soft or hard errors");
525
                        }
526
                }
527
        }
528
        TRACE_EXIT;
529
        return i;
530
}
531
 
532
/*      FDC interrupt service routine.
533
 */
534
void
535
fdc_isr(void)
536
{
537
        TRACE_FUN(8, "fdc_isr");
538
        int result;
539
        int status;
540
        error_cause cause = no_error;
541
        byte in[7];
542
        static int isr_active = 0;
543
        int t0;
544
        buffer_struct *buff = &buffer[head];
545
        int skip;
546
 
547
        t0 = timestamp();
548
        if (isr_active) {
549
                TRACE(-1, "nested interrupt, not good !");
550
                *fdc.hook = fdc_isr;    /* hook our handler into the fdc code again */
551
                TRACE_EXIT;
552
                return;
553
        }
554
        ++isr_active;
555
        sti();                  /* enables interrupts again */
556
        status = inb_p(fdc.msr);
557
        if (status & FDC_BUSY) {        /*  Entering Result Phase */
558
                hide_interrupt = 0;
559
                result = fdc_result(in, 7);     /* better get it fast ! */
560
                if (result < 0) {
561
                        /*  Entered unknown state...
562
                         */
563
                        TRACE(1, "probably fatal error during FDC Result Phase");
564
                        TRACE(1, "drive may hang until (power) reset :-(");
565
                        /*  what to do next ????
566
                         */
567
                } else {
568
                        int i;
569
                        char *fdc_mode_txt;
570
 
571
                        decode_irq_cause(fdc_mode, in, &fdc_mode_txt, &cause);
572
                        for (i = 0; i < NR_BUFFERS; ++i) {
573
                                TRACEx3(8, "buffer[%d] status: %d, segment_id: %d",
574
                                        i, buffer[i].status, buffer[i].segment_id);
575
                        }
576
                        switch (fdc_mode) {
577
 
578
                        case fdc_reading_data:{
579
 
580
                                        if (cause == no_error) {
581
                                                TRACEi(5, "reading segment", buff->segment_id);
582
                                        } else {
583
                                                TRACEi(4, "error reading segment", buff->segment_id);
584
                                        }
585
                                        if (runner_status == aborting || runner_status == do_abort) {
586
                                                TRACEx1(4, "aborting %s", fdc_mode_txt);
587
                                                break;
588
                                        }
589
                                        if (buff->retry > 0) {
590
                                                TRACEx1(5, "this is retry nr %d", buff->retry);
591
                                        }
592
                                        if (buff->bad_sector_map == FAKE_SEGMENT) {
593
                                                /* This condition occurs when reading a `fake' sector that's
594
                                                 * not accessible. Doesn't really matter as we would have
595
                                                 * ignored it anyway !
596
                                                 * Chance is that we're past the next segment now, so the
597
                                                 * next operation may fail and result in a retry.
598
                                                 */
599
                                                TRACE(4, "skipping empty segment (read)");
600
                                                buff->remaining = 0;     /* skip failing sector */
601
                                                continue_xfer(&buff, no_error, fdc_mode, 1);    /* fake success */
602
                                        } else {
603
                                                switch (cause) {
604
                                                case no_error:{
605
                                                                determine_progress(buff, cause, fdc_reading_data);
606
                                                                if (in[2] & 0x40) {
607
                                                                        /*  Handle deleted data in header segments.
608
                                                                         *  Skip segment and force read-ahead.
609
                                                                         */
610
                                                                        TRACEx1(2, "deleted data in sector %d",
611
                                                                                SECTOR(buff->sector_offset - 1));
612
                                                                        buff->deleted = 1;
613
                                                                        buff->remaining = 0;     /* abort transfer */
614
                                                                        buff->soft_error_map |= (-1L << buff->sector_offset);
615
                                                                        if (buff->segment_id == 0) {
616
                                                                                stop_read_ahead = 1;    /* stop on next segment */
617
                                                                        }
618
                                                                        buff->next_segment = buff->segment_id + 1;      /* force read-ahead */
619
                                                                        skip = (SECTORS_PER_SEGMENT - buff->sector_offset);
620
                                                                } else {
621
                                                                        skip = 0;
622
                                                                }
623
                                                                continue_xfer(&buff, cause, fdc_mode, skip);
624
                                                                break;
625
                                                        }
626
                                                case no_data_error:
627
                                                        /*  Tape started too far ahead of or behind the right sector.
628
                                                         *  This may also happen in the middle of a segment !
629
                                                         *  Handle no-data as soft error. If next sector fails too,
630
                                                         *  a retry (with needed reposition) will follow.
631
                                                         */
632
                                                case id_am_error:
633
                                                case id_crc_error:
634
                                                case data_am_error:
635
                                                case data_crc_error:
636
                                                case overrun_error:{
637
                                                                int first_error = (buff->soft_error_map == 0 &&
638
                                                                                   buff->hard_error_map == 0);
639
 
640
                                                                update_history(cause);
641
                                                                determine_progress(buff, cause, fdc_reading_data);
642
                                                                if (first_error) {
643
                                                                        skip = buff->sector_offset;
644
                                                                } else {
645
                                                                        skip = find_resume_point(buff);
646
                                                                }
647
                                                                /*  Try to resume with next sector on single errors (let ecc
648
                                                                 *  correct it), but retry on no_data (we'll be past the
649
                                                                 *  target when we get here so we cannot retry) or on multiple
650
                                                                 *  errors (reduce chance on ecc failure).
651
                                                                 */
652
                                                                if (first_error && cause != no_data_error) {
653
                                                                        continue_xfer(&buff, cause, fdc_mode, skip);
654
                                                                } else {
655
                                                                        retry_sector(&buff, cause, fdc_mode, skip);
656
                                                                }
657
                                                                break;
658
                                                        }
659
                                                default:{
660
                                                                /*  Don't know why this could happen but find out.
661
                                                                 */
662
                                                                TRACE(1, "unexpected error");
663
                                                                determine_progress(buff, cause, fdc_reading_data);
664
                                                                retry_sector(&buff, cause, fdc_mode, 0);
665
                                                                break;
666
                                                        }
667
                                                }
668
                                        }
669
                                        break;
670
                                }
671
 
672
                        case fdc_reading_id:{
673
 
674
                                        if (cause == no_error) {
675
                                                fdc_cyl = in[3];
676
                                                fdc_head = in[4];
677
                                                fdc_sect = in[5];
678
                                                TRACEx3(6, "id read: C: 0x%02x, H: 0x%02x, R: 0x%02x",
679
                                                        fdc_cyl, fdc_head, fdc_sect);
680
                                        } else {        /* no valid information, use invalid sector */
681
                                                fdc_cyl =
682
                                                    fdc_head =
683
                                                    fdc_sect = 0;
684
                                                TRACE(5, "Didn't find valid sector Id");
685
                                        }
686
                                        fdc_mode = fdc_idle;
687
                                        break;
688
                                }
689
 
690
                        case fdc_writing_data:{
691
 
692
                                        if (cause == no_error) {
693
                                                TRACEi(5, "writing segment", buff->segment_id);
694
                                        } else {
695
                                                TRACEi(4, "error writing segment", buff->segment_id);
696
                                        }
697
                                        if (runner_status == aborting || runner_status == do_abort) {
698
                                                TRACEx1(5, "aborting %s", fdc_mode_txt);
699
                                                break;
700
                                        }
701
                                        if (buff->retry > 0) {
702
                                                TRACEx1(5, "this is retry nr %d", buff->retry);
703
                                        }
704
                                        if (buff->bad_sector_map == FAKE_SEGMENT) {
705
                                                /* This condition occurs when trying to write to a `fake'
706
                                                 * sector that's not accessible. Doesn't really matter as
707
                                                 * it isn't used anyway ! Might be located at wrong segment,
708
                                                 * then we'll fail on the next segment.
709
                                                 */
710
                                                TRACE(4, "skipping empty segment (write)");
711
                                                buff->remaining = 0;     /* skip failing sector */
712
                                                continue_xfer(&buff, no_error, fdc_mode, 1);    /* fake success */
713
                                        } else {
714
                                                switch (cause) {
715
                                                case no_error:{
716
                                                                determine_progress(buff, cause, fdc_writing_data);
717
                                                                continue_xfer(&buff, cause, fdc_mode, 0);
718
                                                                break;
719
                                                        }
720
                                                case no_data_error:
721
                                                case id_am_error:
722
                                                case id_crc_error:
723
                                                case data_am_error:
724
                                                case overrun_error:{
725
                                                                update_history(cause);
726
                                                                determine_progress(buff, cause, fdc_writing_data);
727
                                                                skip = find_resume_point(buff);
728
                                                                retry_sector(&buff, cause, fdc_mode, skip);
729
                                                                break;
730
                                                        }
731
                                                default:{
732
                                                                if (in[1] & 0x02) {
733
                                                                        TRACE(1, "media not writable");
734
                                                                } else {
735
                                                                        TRACE(-1, "unforeseen write error");
736
                                                                }
737
                                                                fdc_mode = fdc_idle;
738
                                                                break;
739
                                                        }
740
                                                }
741
                                        }
742
                                        break;
743
                                }
744
                        default:
745
 
746
                                TRACEx1(1, "Warning: unexpected irq during: %s",
747
                                        fdc_mode_txt);
748
                                fdc_mode = fdc_idle;
749
                                break;
750
                        }
751
                }
752
                if (runner_status == do_abort) {
753
                        /*      cease operation, remember tape position
754
                         */
755
                        TRACE(5, "runner aborting");
756
                        runner_status = aborting;
757
                        ++expected_stray_interrupts;
758
                }
759
        } else { /* !FDC_BUSY  */
760
                /*  clear interrupt, cause should be gotten by issuing
761
                 *  a Sense Interrupt Status command.
762
                 */
763
                if (fdc_mode == fdc_recalibrating || fdc_mode == fdc_seeking) {
764
                        if (hide_interrupt) {
765
                                int st0;
766
                                int pcn;
767
 
768
                                result = fdc_sense_interrupt_status(&st0, &pcn);
769
                                current_cylinder = pcn;
770
                                TRACE(5, "handled hidden interrupt");
771
                        }
772
                        seek_completed = 1;
773
                        fdc_mode = fdc_idle;
774
                } else if (!waitqueue_active(&wait_intr)) {
775
                        if (expected_stray_interrupts == 0) {
776
                                TRACE(2, "unexpected stray interrupt");
777
                        } else {
778
                                TRACE(5, "expected stray interrupt");
779
                                --expected_stray_interrupts;
780
                        }
781
                } else {
782
                        if (fdc_mode == fdc_reading_data || fdc_mode == fdc_writing_data ||
783
                            fdc_mode == fdc_reading_id) {
784
                                byte status = inb_p(fdc.msr);
785
                                if (status & FDC_BUSY) {
786
                                        TRACE(-1, "***** FDC failure, busy too late");
787
                                } else {
788
                                        TRACE(-1, "***** FDC failure, no busy");
789
                                }
790
                        } else {
791
                                TRACE(6, "awaited stray interrupt");
792
                        }
793
                }
794
                hide_interrupt = 0;
795
        }
796
        /*    Handle sleep code.
797
         */
798
        if (!hide_interrupt) {
799
                ++interrupt_seen;
800
                if (wait_intr) {
801
                        wake_up_interruptible(&wait_intr);
802
                }
803
        } else {
804
                TRACEx1(5, "hiding interrupt while %s", wait_intr ? "waiting" : "active");
805
        }
806
        t0 = timediff(t0, timestamp());
807
        if (t0 >= 1000) {       /* only tell us about long calls */
808
                TRACEx1(7, "isr() duration: %5d usec", t0);
809
        }
810
        *fdc.hook = fdc_isr;    /* hook our handler into the fdc code again */
811
        TRACE_EXIT;
812
        --isr_active;
813
}

powered by: WebSVN 2.1.0

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