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