This source file includes following definitions.
- print_error_cause
- get_fdc_mode_text
- decode_irq_cause
- update_history
- skip_bad_sector
- update_error_maps
- determine_progress
- calc_steps
- pause_tape
- stop_tape
- continue_xfer
- retry_sector
- find_resume_point
- fdc_isr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
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
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
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
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;
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
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;
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
234
235
236
237
238
239
240
241
242
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
252
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;
267 }
268
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
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
292
293
294
295
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
320
321
322 byte out[3] =
323 {FDC_SEEK, FTAPE_UNIT, 0};
324
325
326
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);
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
363
364 result = fdc_command(out, 3);
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
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);
392 runner_status = aborting;
393 fdc_mode = fdc_idle;
394 }
395 }
396 if (buff->remaining > 0 && calc_next_cluster(&buffer[head]) > 0) {
397
398
399 if (setup_fdc_and_dma(&buffer[head], fdc_op) < 0) {
400
401
402 buff->bytes = buff->ptr - buff->address;
403 buff->status = error;
404 buff = *p_buff = next_buffer(&head);
405 runner_status = aborting;
406 fdc_mode = fdc_idle;
407 }
408 } else {
409
410
411 unsigned last_segment = buff->segment_id;
412 int eot = ((last_segment + 1) % segments_per_track) == 0;
413 int next = buff->next_segment;
414
415 buff->bytes = buff->ptr - buff->address;
416 buff->status = done;
417 buff = *p_buff = next_buffer(&head);
418 if (eot) {
419
420
421 runner_status = logical_eot;
422 fdc_mode = fdc_idle;
423 } else if (next > 0) {
424
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;
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;
451 }
452 } else {
453
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;
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
494
495
496
497
498
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) {
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;
523 } else {
524 TRACE(1, "bug: no soft or hard errors");
525 }
526 }
527 }
528 TRACE_EXIT;
529 return i;
530 }
531
532
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;
551 TRACE_EXIT;
552 return;
553 }
554 ++isr_active;
555 sti();
556 status = inb_p(fdc.msr);
557 if (status & FDC_BUSY) {
558 hide_interrupt = 0;
559 result = fdc_result(in, 7);
560 if (result < 0) {
561
562
563 TRACE(1, "probably fatal error during FDC Result Phase");
564 TRACE(1, "drive may hang until (power) reset :-(");
565
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
594
595
596
597
598
599 TRACE(4, "skipping empty segment (read)");
600 buff->remaining = 0;
601 continue_xfer(&buff, no_error, fdc_mode, 1);
602 } else {
603 switch (cause) {
604 case no_error:{
605 determine_progress(buff, cause, fdc_reading_data);
606 if (in[2] & 0x40) {
607
608
609
610 TRACEx1(2, "deleted data in sector %d",
611 SECTOR(buff->sector_offset - 1));
612 buff->deleted = 1;
613 buff->remaining = 0;
614 buff->soft_error_map |= (-1L << buff->sector_offset);
615 if (buff->segment_id == 0) {
616 stop_read_ahead = 1;
617 }
618 buff->next_segment = buff->segment_id + 1;
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
628
629
630
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
648
649
650
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
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 {
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
706
707
708
709
710 TRACE(4, "skipping empty segment (write)");
711 buff->remaining = 0;
712 continue_xfer(&buff, no_error, fdc_mode, 1);
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, "unforseen 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
754
755 TRACE(5, "runner aborting");
756 runner_status = aborting;
757 ++expected_stray_interrupts;
758 }
759 } else {
760
761
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 (!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
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) {
808 TRACEx1(7, "isr() duration: %5d usec", t0);
809 }
810 *fdc.hook = fdc_isr;
811 TRACE_EXIT;
812 --isr_active;
813 }