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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [ftape/] [lowlevel/] [fdc-isr.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Copyright (C) 1994-1996 Bas Laarhoven,
3
 *                (C) 1996-1997 Claus-Justus Heine.
4
 
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)
8
 any later version.
9
 
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.
14
 
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.
18
 
19
 *
20
 * $Source: /home/marcus/revision_ctrl_test/oc_cvs/cvs/or1k/linux/linux-2.4/drivers/char/ftape/lowlevel/fdc-isr.c,v $
21
 * $Revision: 1.1.1.1 $
22
 * $Date: 2004-04-15 02:02:33 $
23
 *
24
 *      This file contains the interrupt service routine and
25
 *      associated code for the QIC-40/80/3010/3020 floppy-tape driver
26
 *      "ftape" for Linux.
27
 */
28
 
29
#include <asm/io.h>
30
#include <asm/dma.h>
31
 
32
#define volatile                /* */
33
 
34
#include <linux/ftape.h>
35
#include <linux/qic117.h>
36
#include "../lowlevel/ftape-tracing.h"
37
#include "../lowlevel/fdc-isr.h"
38
#include "../lowlevel/fdc-io.h"
39
#include "../lowlevel/ftape-ctl.h"
40
#include "../lowlevel/ftape-rw.h"
41
#include "../lowlevel/ftape-io.h"
42
#include "../lowlevel/ftape-calibr.h"
43
#include "../lowlevel/ftape-bsm.h"
44
 
45
/*      Global vars.
46
 */
47
volatile int ft_expected_stray_interrupts;
48
volatile int ft_interrupt_seen;
49
volatile int ft_seek_completed;
50
volatile int ft_hide_interrupt;
51
/*      Local vars.
52
 */
53
typedef enum {
54
        no_error = 0, id_am_error = 0x01, id_crc_error = 0x02,
55
        data_am_error = 0x04, data_crc_error = 0x08,
56
        no_data_error = 0x10, overrun_error = 0x20,
57
} error_cause;
58
static int stop_read_ahead;
59
 
60
 
61
static void print_error_cause(int cause)
62
{
63
        TRACE_FUN(ft_t_any);
64
 
65
        switch (cause) {
66
        case no_data_error:
67
                TRACE(ft_t_noise, "no data error");
68
                break;
69
        case id_am_error:
70
                TRACE(ft_t_noise, "id am error");
71
                break;
72
        case id_crc_error:
73
                TRACE(ft_t_noise, "id crc error");
74
                break;
75
        case data_am_error:
76
                TRACE(ft_t_noise, "data am error");
77
                break;
78
        case data_crc_error:
79
                TRACE(ft_t_noise, "data crc error");
80
                break;
81
        case overrun_error:
82
                TRACE(ft_t_noise, "overrun error");
83
                break;
84
        default:;
85
        }
86
        TRACE_EXIT;
87
}
88
 
89
static char *fdc_mode_txt(fdc_mode_enum mode)
90
{
91
        switch (mode) {
92
        case fdc_idle:
93
                return "fdc_idle";
94
        case fdc_reading_data:
95
                return "fdc_reading_data";
96
        case fdc_seeking:
97
                return "fdc_seeking";
98
        case fdc_writing_data:
99
                return "fdc_writing_data";
100
        case fdc_reading_id:
101
                return "fdc_reading_id";
102
        case fdc_recalibrating:
103
                return "fdc_recalibrating";
104
        case fdc_formatting:
105
                return "fdc_formatting";
106
        case fdc_verifying:
107
                return "fdc_verifying";
108
        default:
109
                return "unknown";
110
        }
111
}
112
 
113
static inline error_cause decode_irq_cause(fdc_mode_enum mode, __u8 st[])
114
{
115
        error_cause cause = no_error;
116
        TRACE_FUN(ft_t_any);
117
 
118
        /*  Valid st[], decode cause of interrupt.
119
         */
120
        switch (st[0] & ST0_INT_MASK) {
121
        case FDC_INT_NORMAL:
122
                TRACE(ft_t_fdc_dma,"normal completion: %s",fdc_mode_txt(mode));
123
                break;
124
        case FDC_INT_ABNORMAL:
125
                TRACE(ft_t_flow, "abnormal completion %s", fdc_mode_txt(mode));
126
                TRACE(ft_t_fdc_dma, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x",
127
                      st[0], st[1], st[2]);
128
                TRACE(ft_t_fdc_dma,
129
                      "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x",
130
                      st[3], st[4], st[5], st[6]);
131
                if (st[1] & 0x01) {
132
                        if (st[2] & 0x01) {
133
                                cause = data_am_error;
134
                        } else {
135
                                cause = id_am_error;
136
                        }
137
                } else if (st[1] & 0x20) {
138
                        if (st[2] & 0x20) {
139
                                cause = data_crc_error;
140
                        } else {
141
                                cause = id_crc_error;
142
                        }
143
                } else if (st[1] & 0x04) {
144
                        cause = no_data_error;
145
                } else if (st[1] & 0x10) {
146
                        cause = overrun_error;
147
                }
148
                print_error_cause(cause);
149
                break;
150
        case FDC_INT_INVALID:
151
                TRACE(ft_t_flow, "invalid completion %s", fdc_mode_txt(mode));
152
                break;
153
        case FDC_INT_READYCH:
154
                if (st[0] & ST0_SEEK_END) {
155
                        TRACE(ft_t_flow, "drive poll completed");
156
                } else {
157
                        TRACE(ft_t_flow, "ready change %s",fdc_mode_txt(mode));
158
                }
159
                break;
160
        default:
161
                break;
162
        }
163
        TRACE_EXIT cause;
164
}
165
 
166
static void update_history(error_cause cause)
167
{
168
        switch (cause) {
169
        case id_am_error:
170
                ft_history.id_am_errors++;
171
                break;
172
        case id_crc_error:
173
                ft_history.id_crc_errors++;
174
                break;
175
        case data_am_error:
176
                ft_history.data_am_errors++;
177
                break;
178
        case data_crc_error:
179
                ft_history.data_crc_errors++;
180
                break;
181
        case overrun_error:
182
                ft_history.overrun_errors++;
183
                break;
184
        case no_data_error:
185
                ft_history.no_data_errors++;
186
                break;
187
        default:;
188
        }
189
}
190
 
191
static void skip_bad_sector(buffer_struct * buff)
192
{
193
        TRACE_FUN(ft_t_any);
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 += FT_SECTOR_SIZE;
202
                buff->bad_sector_map >>= 1;
203
        } else {
204
                /*  Hey, what is this????????????? C code: if we shift
205
                 *  more than 31 bits, we get no shift. That's bad!!!!!!
206
                 */
207
                ++buff->sector_offset;  /* hack for error maps */
208
                TRACE(ft_t_warn, "skipping last sector in segment");
209
        }
210
        TRACE_EXIT;
211
}
212
 
213
static void update_error_maps(buffer_struct * buff, unsigned int error_offset)
214
{
215
        int hard = 0;
216
        TRACE_FUN(ft_t_any);
217
 
218
        if (buff->retry < FT_SOFT_RETRIES) {
219
                buff->soft_error_map |= (1 << error_offset);
220
        } else {
221
                buff->hard_error_map |= (1 << error_offset);
222
                buff->soft_error_map &= ~buff->hard_error_map;
223
                buff->retry = -1;  /* will be set to 0 in setup_segment */
224
                hard = 1;
225
        }
226
        TRACE(ft_t_noise, "sector %d : %s error\n"
227
              KERN_INFO "hard map: 0x%08lx\n"
228
              KERN_INFO "soft map: 0x%08lx",
229
              FT_SECTOR(error_offset), hard ? "hard" : "soft",
230
              (long) buff->hard_error_map, (long) buff->soft_error_map);
231
        TRACE_EXIT;
232
}
233
 
234
static void print_progress(buffer_struct *buff, error_cause cause)
235
{
236
        TRACE_FUN(ft_t_any);
237
 
238
        switch (cause) {
239
        case no_error:
240
                TRACE(ft_t_flow,"%d Sector(s) transferred", buff->sector_count);
241
                break;
242
        case no_data_error:
243
                TRACE(ft_t_flow, "Sector %d not found",
244
                      FT_SECTOR(buff->sector_offset));
245
                break;
246
        case overrun_error:
247
                /*  got an overrun error on the first byte, must be a
248
                 *  hardware problem
249
                 */
250
                TRACE(ft_t_bug,
251
                      "Unexpected error: failing DMA or FDC controller ?");
252
                break;
253
        case data_crc_error:
254
                TRACE(ft_t_flow, "Error in sector %d",
255
                      FT_SECTOR(buff->sector_offset - 1));
256
                break;
257
        case id_crc_error:
258
        case id_am_error:
259
        case data_am_error:
260
                TRACE(ft_t_flow, "Error in sector %d",
261
                      FT_SECTOR(buff->sector_offset));
262
                break;
263
        default:
264
                TRACE(ft_t_flow, "Unexpected error at sector %d",
265
                      FT_SECTOR(buff->sector_offset));
266
                break;
267
        }
268
        TRACE_EXIT;
269
}
270
 
271
/*
272
 *  Error cause:   Amount xferred:  Action:
273
 *
274
 *  id_am_error         0           mark bad and skip
275
 *  id_crc_error        0           mark bad and skip
276
 *  data_am_error       0           mark bad and skip
277
 *  data_crc_error    % 1024        mark bad and skip
278
 *  no_data_error       0           retry on write
279
 *                                  mark bad and skip on read
280
 *  overrun_error  [ 0..all-1 ]     mark bad and skip
281
 *  no_error           all          continue
282
 */
283
 
284
/*  the arg `sector' is returned by the fdc and tells us at which sector we
285
 *  are positioned at (relative to starting sector of segment)
286
 */
287
static void determine_verify_progress(buffer_struct *buff,
288
                                      error_cause cause,
289
                                      __u8 sector)
290
{
291
        TRACE_FUN(ft_t_any);
292
 
293
        if (cause == no_error && sector == 1) {
294
                buff->sector_offset = FT_SECTORS_PER_SEGMENT;
295
                buff->remaining     = 0;
296
                if (TRACE_LEVEL >= ft_t_flow) {
297
                        print_progress(buff, cause);
298
                }
299
        } else {
300
                buff->sector_offset = sector - buff->sect;
301
                buff->remaining = FT_SECTORS_PER_SEGMENT - buff->sector_offset;
302
                TRACE(ft_t_noise, "%ssector offset: 0x%04x",
303
                      (cause == no_error) ? "unexpected " : "",
304
                      buff->sector_offset);
305
                switch (cause) {
306
                case overrun_error:
307
                        break;
308
#if 0
309
                case no_data_error:
310
                        buff->retry = FT_SOFT_RETRIES;
311
                        if (buff->hard_error_map    &&
312
                            buff->sector_offset > 1 &&
313
                            (buff->hard_error_map &
314
                             (1 << (buff->sector_offset-2)))) {
315
                                buff->retry --;
316
                        }
317
                        break;
318
#endif
319
                default:
320
                        buff->retry = FT_SOFT_RETRIES;
321
                        break;
322
                }
323
                if (TRACE_LEVEL >= ft_t_flow) {
324
                        print_progress(buff, cause);
325
                }
326
                /*  Sector_offset points to the problem area Now adjust
327
                 *  sector_offset so it always points one past he failing
328
                 *  sector. I.e. skip the bad sector.
329
                 */
330
                ++buff->sector_offset;
331
                --buff->remaining;
332
                update_error_maps(buff, buff->sector_offset - 1);
333
        }
334
        TRACE_EXIT;
335
}
336
 
337
static void determine_progress(buffer_struct *buff,
338
                               error_cause cause,
339
                               __u8 sector)
340
{
341
        unsigned int dma_residue;
342
        TRACE_FUN(ft_t_any);
343
 
344
        /*  Using less preferred order of disable_dma and
345
         *  get_dma_residue because this seems to fail on at least one
346
         *  system if reversed!
347
         */
348
        dma_residue = get_dma_residue(fdc.dma);
349
        disable_dma(fdc.dma);
350
        if (cause != no_error || dma_residue != 0) {
351
                TRACE(ft_t_noise, "%sDMA residue: 0x%04x",
352
                      (cause == no_error) ? "unexpected " : "",
353
                      dma_residue);
354
                /* adjust to actual value: */
355
                if (dma_residue == 0) {
356
                        /* this happens sometimes with overrun errors.
357
                         * I don't know whether we could ignore the
358
                         * overrun error. Play save.
359
                         */
360
                        buff->sector_count --;
361
                } else {
362
                        buff->sector_count -= ((dma_residue +
363
                                                (FT_SECTOR_SIZE - 1)) /
364
                                               FT_SECTOR_SIZE);
365
                }
366
        }
367
        /*  Update var's influenced by the DMA operation.
368
         */
369
        if (buff->sector_count > 0) {
370
                buff->sector_offset   += buff->sector_count;
371
                buff->data_offset     += buff->sector_count;
372
                buff->ptr             += (buff->sector_count *
373
                                          FT_SECTOR_SIZE);
374
                buff->remaining       -= buff->sector_count;
375
                buff->bad_sector_map >>= buff->sector_count;
376
        }
377
        if (TRACE_LEVEL >= ft_t_flow) {
378
                print_progress(buff, cause);
379
        }
380
        if (cause != no_error) {
381
                if (buff->remaining == 0) {
382
                        TRACE(ft_t_warn, "foo?\n"
383
                              KERN_INFO "count : %d\n"
384
                              KERN_INFO "offset: %d\n"
385
                              KERN_INFO "soft  : %08x\n"
386
                              KERN_INFO "hard  : %08x",
387
                              buff->sector_count,
388
                              buff->sector_offset,
389
                              buff->soft_error_map,
390
                              buff->hard_error_map);
391
                }
392
                /*  Sector_offset points to the problem area, except if we got
393
                 *  a data_crc_error. In that case it points one past the
394
                 *  failing sector.
395
                 *
396
                 *  Now adjust sector_offset so it always points one past he
397
                 *  failing sector. I.e. skip the bad sector.
398
                 */
399
                if (cause != data_crc_error) {
400
                        skip_bad_sector(buff);
401
                }
402
                update_error_maps(buff, buff->sector_offset - 1);
403
        }
404
        TRACE_EXIT;
405
}
406
 
407
static int calc_steps(int cmd)
408
{
409
        if (ftape_current_cylinder > cmd) {
410
                return ftape_current_cylinder - cmd;
411
        } else {
412
                return ftape_current_cylinder + cmd;
413
        }
414
}
415
 
416
static void pause_tape(int retry, int mode)
417
{
418
        int result;
419
        __u8 out[3] = {FDC_SEEK, ft_drive_sel, 0};
420
        TRACE_FUN(ft_t_any);
421
 
422
        /*  We'll use a raw seek command to get the tape to rewind and
423
         *  stop for a retry.
424
         */
425
        ++ft_history.rewinds;
426
        if (qic117_cmds[ftape_current_command].non_intr) {
427
                TRACE(ft_t_warn, "motion command may be issued too soon");
428
        }
429
        if (retry && (mode == fdc_reading_data ||
430
                      mode == fdc_reading_id   ||
431
                      mode == fdc_verifying)) {
432
                ftape_current_command = QIC_MICRO_STEP_PAUSE;
433
                ftape_might_be_off_track = 1;
434
        } else {
435
                ftape_current_command = QIC_PAUSE;
436
        }
437
        out[2] = calc_steps(ftape_current_command);
438
        result = fdc_command(out, 3); /* issue QIC_117 command */
439
        ftape_current_cylinder = out[ 2];
440
        if (result < 0) {
441
                TRACE(ft_t_noise, "qic-pause failed, status = %d", result);
442
        } else {
443
                ft_location.known  = 0;
444
                ft_runner_status   = idle;
445
                ft_hide_interrupt     = 1;
446
                ftape_tape_running = 0;
447
        }
448
        TRACE_EXIT;
449
}
450
 
451
static void continue_xfer(buffer_struct *buff,
452
                          fdc_mode_enum mode,
453
                          unsigned int skip)
454
{
455
        int write = 0;
456
        TRACE_FUN(ft_t_any);
457
 
458
        if (mode == fdc_writing_data || mode == fdc_deleting) {
459
                write = 1;
460
        }
461
        /*  This part can be removed if it never happens
462
         */
463
        if (skip > 0 &&
464
            (ft_runner_status != running ||
465
             (write && (buff->status != writing)) ||
466
             (!write && (buff->status != reading &&
467
                         buff->status != verifying)))) {
468
                TRACE(ft_t_err, "unexpected runner/buffer state %d/%d",
469
                      ft_runner_status, buff->status);
470
                buff->status = error;
471
                /* finish this buffer: */
472
                (void)ftape_next_buffer(ft_queue_head);
473
                ft_runner_status = aborting;
474
                fdc_mode         = fdc_idle;
475
        } else if (buff->remaining > 0 && ftape_calc_next_cluster(buff) > 0) {
476
                /*  still sectors left in current segment, continue
477
                 *  with this segment
478
                 */
479
                if (fdc_setup_read_write(buff, mode) < 0) {
480
                        /* failed, abort operation
481
                         */
482
                        buff->bytes = buff->ptr - buff->address;
483
                        buff->status = error;
484
                        /* finish this buffer: */
485
                        (void)ftape_next_buffer(ft_queue_head);
486
                        ft_runner_status = aborting;
487
                        fdc_mode         = fdc_idle;
488
                }
489
        } else {
490
                /* current segment completed
491
                 */
492
                unsigned int last_segment = buff->segment_id;
493
                int eot = ((last_segment + 1) % ft_segments_per_track) == 0;
494
                unsigned int next = buff->next_segment; /* 0 means stop ! */
495
 
496
                buff->bytes = buff->ptr - buff->address;
497
                buff->status = done;
498
                buff = ftape_next_buffer(ft_queue_head);
499
                if (eot) {
500
                        /*  finished last segment on current track,
501
                         *  can't continue
502
                         */
503
                        ft_runner_status = logical_eot;
504
                        fdc_mode         = fdc_idle;
505
                        TRACE_EXIT;
506
                }
507
                if (next <= 0) {
508
                        /*  don't continue with next segment
509
                         */
510
                        TRACE(ft_t_noise, "no %s allowed, stopping tape",
511
                              (write) ? "write next" : "read ahead");
512
                        pause_tape(0, mode);
513
                        ft_runner_status = idle;  /*  not quite true until
514
                                                   *  next irq
515
                                                   */
516
                        TRACE_EXIT;
517
                }
518
                /*  continue with next segment
519
                 */
520
                if (buff->status != waiting) {
521
                        TRACE(ft_t_noise, "all input buffers %s, pausing tape",
522
                              (write) ? "empty" : "full");
523
                        pause_tape(0, mode);
524
                        ft_runner_status = idle;  /*  not quite true until
525
                                                   *  next irq
526
                                                   */
527
                        TRACE_EXIT;
528
                }
529
                if (write && next != buff->segment_id) {
530
                        TRACE(ft_t_noise,
531
                              "segments out of order, aborting write");
532
                        ft_runner_status = do_abort;
533
                        fdc_mode         = fdc_idle;
534
                        TRACE_EXIT;
535
                }
536
                ftape_setup_new_segment(buff, next, 0);
537
                if (stop_read_ahead) {
538
                        buff->next_segment = 0;
539
                        stop_read_ahead = 0;
540
                }
541
                if (ftape_calc_next_cluster(buff) == 0 ||
542
                    fdc_setup_read_write(buff, mode) != 0) {
543
                        TRACE(ft_t_err, "couldn't start %s-ahead",
544
                              write ? "write" : "read");
545
                        ft_runner_status = do_abort;
546
                        fdc_mode         = fdc_idle;
547
                } else {
548
                        /* keep on going */
549
                        switch (ft_driver_state) {
550
                        case   reading: buff->status = reading;   break;
551
                        case verifying: buff->status = verifying; break;
552
                        case   writing: buff->status = writing;   break;
553
                        case  deleting: buff->status = deleting;  break;
554
                        default:
555
                                TRACE(ft_t_err,
556
                      "BUG: ft_driver_state %d should be one out of "
557
                      "{reading, writing, verifying, deleting}",
558
                                      ft_driver_state);
559
                                buff->status = write ? writing : reading;
560
                                break;
561
                        }
562
                }
563
        }
564
        TRACE_EXIT;
565
}
566
 
567
static void retry_sector(buffer_struct *buff,
568
                         int mode,
569
                         unsigned int skip)
570
{
571
        TRACE_FUN(ft_t_any);
572
 
573
        TRACE(ft_t_noise, "%s error, will retry",
574
              (mode == fdc_writing_data || mode == fdc_deleting) ? "write" : "read");
575
        pause_tape(1, mode);
576
        ft_runner_status = aborting;
577
        buff->status     = error;
578
        buff->skip       = skip;
579
        TRACE_EXIT;
580
}
581
 
582
static unsigned int find_resume_point(buffer_struct *buff)
583
{
584
        int i = 0;
585
        SectorMap mask;
586
        SectorMap map;
587
        TRACE_FUN(ft_t_any);
588
 
589
        /*  This function is to be called after all variables have been
590
         *  updated to point past the failing sector.
591
         *  If there are any soft errors before the failing sector,
592
         *  find the first soft error and return the sector offset.
593
         *  Otherwise find the last hard error.
594
         *  Note: there should always be at least one hard or soft error !
595
         */
596
        if (buff->sector_offset < 1 || buff->sector_offset > 32) {
597
                TRACE(ft_t_bug, "BUG: sector_offset = %d",
598
                      buff->sector_offset);
599
                TRACE_EXIT 0;
600
        }
601
        if (buff->sector_offset >= 32) { /* C-limitation on shift ! */
602
                mask = 0xffffffff;
603
        } else {
604
                mask = (1 << buff->sector_offset) - 1;
605
        }
606
        map = buff->soft_error_map & mask;
607
        if (map) {
608
                while ((map & (1 << i)) == 0) {
609
                        ++i;
610
                }
611
                TRACE(ft_t_noise, "at sector %d", FT_SECTOR(i));
612
        } else {
613
                map = buff->hard_error_map & mask;
614
                i = buff->sector_offset - 1;
615
                if (map) {
616
                        while ((map & (1 << i)) == 0) {
617
                                --i;
618
                        }
619
                        TRACE(ft_t_noise, "after sector %d", FT_SECTOR(i));
620
                        ++i; /* first sector after last hard error */
621
                } else {
622
                        TRACE(ft_t_bug, "BUG: no soft or hard errors");
623
                }
624
        }
625
        TRACE_EXIT i;
626
}
627
 
628
/*  check possible dma residue when formatting, update position record in
629
 *  buffer struct. This is, of course, modelled after determine_progress(), but
630
 *  we don't need to set up for retries because the format process cannot be
631
 *  interrupted (except at the end of the tape track).
632
 */
633
static int determine_fmt_progress(buffer_struct *buff, error_cause cause)
634
{
635
        unsigned int dma_residue;
636
        TRACE_FUN(ft_t_any);
637
 
638
        /*  Using less preferred order of disable_dma and
639
         *  get_dma_residue because this seems to fail on at least one
640
         *  system if reversed!
641
         */
642
        dma_residue = get_dma_residue(fdc.dma);
643
        disable_dma(fdc.dma);
644
        if (cause != no_error || dma_residue != 0) {
645
                TRACE(ft_t_info, "DMA residue = 0x%04x", dma_residue);
646
                fdc_mode = fdc_idle;
647
                switch(cause) {
648
                case no_error:
649
                        ft_runner_status = aborting;
650
                        buff->status = idle;
651
                        break;
652
                case overrun_error:
653
                        /*  got an overrun error on the first byte, must be a
654
                         *  hardware problem
655
                         */
656
                        TRACE(ft_t_bug,
657
                              "Unexpected error: failing DMA controller ?");
658
                        ft_runner_status = do_abort;
659
                        buff->status = error;
660
                        break;
661
                default:
662
                        TRACE(ft_t_noise, "Unexpected error at segment %d",
663
                              buff->segment_id);
664
                        ft_runner_status = do_abort;
665
                        buff->status = error;
666
                        break;
667
                }
668
                TRACE_EXIT -EIO; /* can only retry entire track in format mode
669
                                  */
670
        }
671
        /*  Update var's influenced by the DMA operation.
672
         */
673
        buff->ptr             += FT_SECTORS_PER_SEGMENT * 4;
674
        buff->bytes           -= FT_SECTORS_PER_SEGMENT * 4;
675
        buff->remaining       -= FT_SECTORS_PER_SEGMENT;
676
        buff->segment_id ++; /* done with segment */
677
        TRACE_EXIT 0;
678
}
679
 
680
/*
681
 *  Continue formatting, switch buffers if there is no data left in
682
 *  current buffer. This is, of course, modelled after
683
 *  continue_xfer(), but we don't need to set up for retries because
684
 *  the format process cannot be interrupted (except at the end of the
685
 *  tape track).
686
 */
687
static void continue_formatting(buffer_struct *buff)
688
{
689
        TRACE_FUN(ft_t_any);
690
 
691
        if (buff->remaining <= 0) { /*  no space left in dma buffer */
692
                unsigned int next = buff->next_segment;
693
 
694
                if (next == 0) { /* end of tape track */
695
                        buff->status     = done;
696
                        ft_runner_status = logical_eot;
697
                        fdc_mode         = fdc_idle;
698
                        TRACE(ft_t_noise, "Done formatting track %d",
699
                              ft_location.track);
700
                        TRACE_EXIT;
701
                }
702
                /*
703
                 *  switch to next buffer!
704
                 */
705
                buff->status   = done;
706
                buff = ftape_next_buffer(ft_queue_head);
707
 
708
                if (buff->status != waiting  || next != buff->segment_id) {
709
                        goto format_setup_error;
710
                }
711
        }
712
        if (fdc_setup_formatting(buff) < 0) {
713
                goto format_setup_error;
714
        }
715
        buff->status = formatting;
716
        TRACE(ft_t_fdc_dma, "Formatting segment %d on track %d",
717
              buff->segment_id, ft_location.track);
718
        TRACE_EXIT;
719
 format_setup_error:
720
        ft_runner_status = do_abort;
721
        fdc_mode         = fdc_idle;
722
        buff->status     = error;
723
        TRACE(ft_t_err, "Error setting up for segment %d on track %d",
724
              buff->segment_id, ft_location.track);
725
        TRACE_EXIT;
726
 
727
}
728
 
729
/*  this handles writing, read id, reading and formatting
730
 */
731
static void handle_fdc_busy(buffer_struct *buff)
732
{
733
        static int no_data_error_count;
734
        int retry = 0;
735
        error_cause cause;
736
        __u8 in[7];
737
        int skip;
738
        fdc_mode_enum fmode = fdc_mode;
739
        TRACE_FUN(ft_t_any);
740
 
741
        if (fdc_result(in, 7) < 0) { /* better get it fast ! */
742
                TRACE(ft_t_err,
743
                      "Probably fatal error during FDC Result Phase\n"
744
                      KERN_INFO
745
                      "drive may hang until (power on) reset :-(");
746
                /*  what to do next ????
747
                 */
748
                TRACE_EXIT;
749
        }
750
        cause = decode_irq_cause(fdc_mode, in);
751
#ifdef TESTING
752
        { int i;
753
        for (i = 0; i < (int)ft_nr_buffers; ++i)
754
                TRACE(ft_t_any, "buffer[%d] status: %d, segment_id: %d",
755
                      i, ft_buffer[i]->status, ft_buffer[i]->segment_id);
756
        }
757
#endif
758
        if (fmode == fdc_reading_data && ft_driver_state == verifying) {
759
                fmode = fdc_verifying;
760
        }
761
        switch (fmode) {
762
        case fdc_verifying:
763
                if (ft_runner_status == aborting ||
764
                    ft_runner_status == do_abort) {
765
                        TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode));
766
                        break;
767
                }
768
                if (buff->retry > 0) {
769
                        TRACE(ft_t_flow, "this is retry nr %d", buff->retry);
770
                }
771
                switch (cause) {
772
                case no_error:
773
                        no_data_error_count = 0;
774
                        determine_verify_progress(buff, cause, in[5]);
775
                        if (in[2] & 0x40) {
776
                                /*  This should not happen when verifying
777
                                 */
778
                                TRACE(ft_t_warn,
779
                                      "deleted data in segment %d/%d",
780
                                      buff->segment_id,
781
                                      FT_SECTOR(buff->sector_offset - 1));
782
                                buff->remaining = 0; /* abort transfer */
783
                                buff->hard_error_map = EMPTY_SEGMENT;
784
                                skip = 1;
785
                        } else {
786
                                skip = 0;
787
                        }
788
                        continue_xfer(buff, fdc_mode, skip);
789
                        break;
790
                case no_data_error:
791
                        no_data_error_count ++;
792
                case overrun_error:
793
                        retry ++;
794
                case id_am_error:
795
                case id_crc_error:
796
                case data_am_error:
797
                case data_crc_error:
798
                        determine_verify_progress(buff, cause, in[5]);
799
                        if (cause == no_data_error) {
800
                                if (no_data_error_count >= 2) {
801
                                        TRACE(ft_t_warn,
802
                                              "retrying because of successive "
803
                                              "no data errors");
804
                                        no_data_error_count = 0;
805
                                } else {
806
                                        retry --;
807
                                }
808
                        } else {
809
                                no_data_error_count = 0;
810
                        }
811
                        if (retry) {
812
                                skip = find_resume_point(buff);
813
                        } else {
814
                                skip = buff->sector_offset;
815
                        }
816
                        if (retry && skip < 32) {
817
                                retry_sector(buff, fdc_mode, skip);
818
                        } else {
819
                                continue_xfer(buff, fdc_mode, skip);
820
                        }
821
                        update_history(cause);
822
                        break;
823
                default:
824
                        /*  Don't know why this could happen
825
                         *  but find out.
826
                         */
827
                        determine_verify_progress(buff, cause, in[5]);
828
                        retry_sector(buff, fdc_mode, 0);
829
                        TRACE(ft_t_err, "Error: unexpected error");
830
                        break;
831
                }
832
                break;
833
        case fdc_reading_data:
834
#ifdef TESTING
835
                /* I'm sorry, but: NOBODY ever used this trace
836
                 * messages for ages. I guess that Bas was the last person
837
                 * that ever really used this (thank you, between the lines)
838
                 */
839
                if (cause == no_error) {
840
                        TRACE(ft_t_flow,"reading segment %d",buff->segment_id);
841
                } else {
842
                        TRACE(ft_t_noise, "error reading segment %d",
843
                              buff->segment_id);
844
                        TRACE(ft_t_noise, "\n"
845
                              KERN_INFO
846
                             "IRQ:C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x\n"
847
                              KERN_INFO
848
                              "BUF:C: 0x%02x, H: 0x%02x, R: 0x%02x",
849
                              in[3], in[4], in[5], in[6],
850
                              buff->cyl, buff->head, buff->sect);
851
                }
852
#endif
853
                if (ft_runner_status == aborting ||
854
                    ft_runner_status == do_abort) {
855
                        TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode));
856
                        break;
857
                }
858
                if (buff->bad_sector_map == FAKE_SEGMENT) {
859
                        /* This condition occurs when reading a `fake'
860
                         * sector that's not accessible. Doesn't
861
                         * really matter as we would have ignored it
862
                         * anyway !
863
                         *
864
                         * Chance is that we're past the next segment
865
                         * now, so the next operation may fail and
866
                         * result in a retry.
867
                         */
868
                        buff->remaining = 0;     /* skip failing sector */
869
                        /* buff->ptr       = buff->address; */
870
                        /* fake success: */
871
                        continue_xfer(buff, fdc_mode, 1);
872
                        /*  trace calls are expensive: place them AFTER
873
                         *  the real stuff has been done.
874
                         *
875
                         */
876
                        TRACE(ft_t_noise, "skipping empty segment %d (read), size? %d",
877
                              buff->segment_id, buff->ptr - buff->address);
878
                        TRACE_EXIT;
879
                }
880
                if (buff->retry > 0) {
881
                        TRACE(ft_t_flow, "this is retry nr %d", buff->retry);
882
                }
883
                switch (cause) {
884
                case no_error:
885
                        determine_progress(buff, cause, in[5]);
886
                        if (in[2] & 0x40) {
887
                                /*  Handle deleted data in header segments.
888
                                 *  Skip segment and force read-ahead.
889
                                 */
890
                                TRACE(ft_t_warn,
891
                                      "deleted data in segment %d/%d",
892
                                      buff->segment_id,
893
                                      FT_SECTOR(buff->sector_offset - 1));
894
                                buff->deleted = 1;
895
                                buff->remaining = 0;/*abort transfer */
896
                                buff->soft_error_map |=
897
                                                (-1L << buff->sector_offset);
898
                                if (buff->segment_id == 0) {
899
                                        /* stop on next segment */
900
                                        stop_read_ahead = 1;
901
                                }
902
                                /* force read-ahead: */
903
                                buff->next_segment =
904
                                        buff->segment_id + 1;
905
                                skip = (FT_SECTORS_PER_SEGMENT -
906
                                        buff->sector_offset);
907
                        } else {
908
                                skip = 0;
909
                        }
910
                        continue_xfer(buff, fdc_mode, skip);
911
                        break;
912
                case no_data_error:
913
                        /* Tape started too far ahead of or behind the
914
                         * right sector.  This may also happen in the
915
                         * middle of a segment !
916
                         *
917
                         * Handle no-data as soft error. If next
918
                         * sector fails too, a retry (with needed
919
                         * reposition) will follow.
920
                         */
921
                        retry ++;
922
                case id_am_error:
923
                case id_crc_error:
924
                case data_am_error:
925
                case data_crc_error:
926
                case overrun_error:
927
                        retry += (buff->soft_error_map != 0 ||
928
                                  buff->hard_error_map != 0);
929
                        determine_progress(buff, cause, in[5]);
930
#if 1 || defined(TESTING)
931
                        if (cause == overrun_error) retry ++;
932
#endif
933
                        if (retry) {
934
                                skip = find_resume_point(buff);
935
                        } else {
936
                                skip = buff->sector_offset;
937
                        }
938
                        /*  Try to resume with next sector on single
939
                         *  errors (let ecc correct it), but retry on
940
                         *  no_data (we'll be past the target when we
941
                         *  get here so we cannot retry) or on
942
                         *  multiple errors (reduce chance on ecc
943
                         *  failure).
944
                         */
945
                        /*  cH: 23/02/97: if the last sector in the
946
                         *  segment was a hard error, then there is
947
                         *  no sense in a retry. This occasion seldom
948
                         *  occurs but ... @:³²¸`@%&§$
949
                         */
950
                        if (retry && skip < 32) {
951
                                retry_sector(buff, fdc_mode, skip);
952
                        } else {
953
                                continue_xfer(buff, fdc_mode, skip);
954
                        }
955
                        update_history(cause);
956
                        break;
957
                default:
958
                        /*  Don't know why this could happen
959
                         *  but find out.
960
                         */
961
                        determine_progress(buff, cause, in[5]);
962
                        retry_sector(buff, fdc_mode, 0);
963
                        TRACE(ft_t_err, "Error: unexpected error");
964
                        break;
965
                }
966
                break;
967
        case fdc_reading_id:
968
                if (cause == no_error) {
969
                        fdc_cyl = in[3];
970
                        fdc_head = in[4];
971
                        fdc_sect = in[5];
972
                        TRACE(ft_t_fdc_dma,
973
                              "id read: C: 0x%02x, H: 0x%02x, R: 0x%02x",
974
                              fdc_cyl, fdc_head, fdc_sect);
975
                } else {        /* no valid information, use invalid sector */
976
                        fdc_cyl = fdc_head = fdc_sect = 0;
977
                        TRACE(ft_t_flow, "Didn't find valid sector Id");
978
                }
979
                fdc_mode = fdc_idle;
980
                break;
981
        case fdc_deleting:
982
        case fdc_writing_data:
983
#ifdef TESTING
984
                if (cause == no_error) {
985
                        TRACE(ft_t_flow, "writing segment %d", buff->segment_id);
986
                } else {
987
                        TRACE(ft_t_noise, "error writing segment %d",
988
                              buff->segment_id);
989
                }
990
#endif
991
                if (ft_runner_status == aborting ||
992
                    ft_runner_status == do_abort) {
993
                        TRACE(ft_t_flow, "aborting %s",fdc_mode_txt(fdc_mode));
994
                        break;
995
                }
996
                if (buff->retry > 0) {
997
                        TRACE(ft_t_flow, "this is retry nr %d", buff->retry);
998
                }
999
                if (buff->bad_sector_map == FAKE_SEGMENT) {
1000
                        /* This condition occurs when trying to write to a
1001
                         * `fake' sector that's not accessible. Doesn't really
1002
                         * matter as it isn't used anyway ! Might be located
1003
                         * at wrong segment, then we'll fail on the next
1004
                         * segment.
1005
                         */
1006
                        TRACE(ft_t_noise, "skipping empty segment (write)");
1007
                        buff->remaining = 0;     /* skip failing sector */
1008
                        /* fake success: */
1009
                        continue_xfer(buff, fdc_mode, 1);
1010
                        break;
1011
                }
1012
                switch (cause) {
1013
                case no_error:
1014
                        determine_progress(buff, cause, in[5]);
1015
                        continue_xfer(buff, fdc_mode, 0);
1016
                        break;
1017
                case no_data_error:
1018
                case id_am_error:
1019
                case id_crc_error:
1020
                case data_am_error:
1021
                case overrun_error:
1022
                        update_history(cause);
1023
                        determine_progress(buff, cause, in[5]);
1024
                        skip = find_resume_point(buff);
1025
                        retry_sector(buff, fdc_mode, skip);
1026
                        break;
1027
                default:
1028
                        if (in[1] & 0x02) {
1029
                                TRACE(ft_t_err, "media not writable");
1030
                        } else {
1031
                                TRACE(ft_t_bug, "unforeseen write error");
1032
                        }
1033
                        fdc_mode = fdc_idle;
1034
                        break;
1035
                }
1036
                break; /* fdc_deleting || fdc_writing_data */
1037
        case fdc_formatting:
1038
                /*  The interrupt comes after formatting a segment. We then
1039
                 *  have to set up QUICKLY for the next segment. But
1040
                 *  afterwards, there is plenty of time.
1041
                 */
1042
                switch (cause) {
1043
                case no_error:
1044
                        /*  would like to keep most of the formatting stuff
1045
                         *  outside the isr code, but timing is too critical
1046
                         */
1047
                        if (determine_fmt_progress(buff, cause) >= 0) {
1048
                                continue_formatting(buff);
1049
                        }
1050
                        break;
1051
                case no_data_error:
1052
                case id_am_error:
1053
                case id_crc_error:
1054
                case data_am_error:
1055
                case overrun_error:
1056
                default:
1057
                        determine_fmt_progress(buff, cause);
1058
                        update_history(cause);
1059
                        if (in[1] & 0x02) {
1060
                                TRACE(ft_t_err, "media not writable");
1061
                        } else {
1062
                                TRACE(ft_t_bug, "unforeseen write error");
1063
                        }
1064
                        break;
1065
                } /* cause */
1066
                break;
1067
        default:
1068
                TRACE(ft_t_warn, "Warning: unexpected irq during: %s",
1069
                      fdc_mode_txt(fdc_mode));
1070
                fdc_mode = fdc_idle;
1071
                break;
1072
        }
1073
        TRACE_EXIT;
1074
}
1075
 
1076
/*      FDC interrupt service routine.
1077
 */
1078
void fdc_isr(void)
1079
{
1080
        static int isr_active;
1081
#ifdef TESTING
1082
        unsigned int t0 = ftape_timestamp();
1083
#endif
1084
        TRACE_FUN(ft_t_any);
1085
 
1086
        if (isr_active++) {
1087
                --isr_active;
1088
                TRACE(ft_t_bug, "BUG: nested interrupt, not good !");
1089
                *fdc.hook = fdc_isr; /*  hook our handler into the fdc
1090
                                      *  code again
1091
                                      */
1092
                TRACE_EXIT;
1093
        }
1094
        sti();
1095
        if (inb_p(fdc.msr) & FDC_BUSY) {        /*  Entering Result Phase */
1096
                ft_hide_interrupt = 0;
1097
                handle_fdc_busy(ftape_get_buffer(ft_queue_head));
1098
                if (ft_runner_status == do_abort) {
1099
                        /*      cease operation, remember tape position
1100
                         */
1101
                        TRACE(ft_t_flow, "runner aborting");
1102
                        ft_runner_status = aborting;
1103
                        ++ft_expected_stray_interrupts;
1104
                }
1105
        } else { /* !FDC_BUSY */
1106
                /*  clear interrupt, cause should be gotten by issuing
1107
                 *  a Sense Interrupt Status command.
1108
                 */
1109
                if (fdc_mode == fdc_recalibrating || fdc_mode == fdc_seeking) {
1110
                        if (ft_hide_interrupt) {
1111
                                int st0;
1112
                                int pcn;
1113
 
1114
                                if (fdc_sense_interrupt_status(&st0, &pcn) < 0)
1115
                                        TRACE(ft_t_err,
1116
                                              "sense interrupt status failed");
1117
                                ftape_current_cylinder = pcn;
1118
                                TRACE(ft_t_flow, "handled hidden interrupt");
1119
                        }
1120
                        ft_seek_completed = 1;
1121
                        fdc_mode = fdc_idle;
1122
#if LINUX_VERSION_CODE >= KERNEL_VER(2,0,16)
1123
                } else if (!waitqueue_active(&ftape_wait_intr)) {
1124
#else
1125
                } else if (!ftape_wait_intr) {
1126
#endif
1127
                        if (ft_expected_stray_interrupts == 0) {
1128
                                TRACE(ft_t_warn, "unexpected stray interrupt");
1129
                        } else {
1130
                                TRACE(ft_t_flow, "expected stray interrupt");
1131
                                --ft_expected_stray_interrupts;
1132
                        }
1133
                } else {
1134
                        if (fdc_mode == fdc_reading_data ||
1135
                            fdc_mode == fdc_verifying    ||
1136
                            fdc_mode == fdc_writing_data ||
1137
                            fdc_mode == fdc_deleting     ||
1138
                            fdc_mode == fdc_formatting   ||
1139
                            fdc_mode == fdc_reading_id) {
1140
                                if (inb_p(fdc.msr) & FDC_BUSY) {
1141
                                        TRACE(ft_t_bug,
1142
                                        "***** FDC failure, busy too late");
1143
                                } else {
1144
                                        TRACE(ft_t_bug,
1145
                                              "***** FDC failure, no busy");
1146
                                }
1147
                        } else {
1148
                                TRACE(ft_t_fdc_dma, "awaited stray interrupt");
1149
                        }
1150
                }
1151
                ft_hide_interrupt = 0;
1152
        }
1153
        /*    Handle sleep code.
1154
         */
1155
        if (!ft_hide_interrupt) {
1156
                ft_interrupt_seen ++;
1157
#if LINUX_VERSION_CODE >= KERNEL_VER(2,0,16)
1158
                if (waitqueue_active(&ftape_wait_intr)) {
1159
                        wake_up_interruptible(&ftape_wait_intr);
1160
                }
1161
#else
1162
                if (ftape_wait_intr) {
1163
                        wake_up_interruptible(&ftape_wait_intr);
1164
                }
1165
#endif
1166
        } else {
1167
#if LINUX_VERSION_CODE >= KERNEL_VER(2,0,16)
1168
                TRACE(ft_t_flow, "hiding interrupt while %s",
1169
                      waitqueue_active(&ftape_wait_intr) ? "waiting":"active");
1170
#else
1171
                TRACE(ft_t_flow, "hiding interrupt while %s",
1172
                      ftape_wait_intr ? "waiting" : "active");
1173
#endif
1174
        }
1175
#ifdef TESTING
1176
        t0 = ftape_timediff(t0, ftape_timestamp());
1177
        if (t0 >= 1000) {
1178
                /* only tell us about long calls */
1179
                TRACE(ft_t_noise, "isr() duration: %5d usec", t0);
1180
        }
1181
#endif
1182
        *fdc.hook = fdc_isr;    /* hook our handler into the fdc code again */
1183
        --isr_active;
1184
        TRACE_EXIT;
1185
}

powered by: WebSVN 2.1.0

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