diff options
Diffstat (limited to 'drivers/char/ftape/lowlevel')
35 files changed, 0 insertions, 10776 deletions
diff --git a/drivers/char/ftape/lowlevel/Makefile b/drivers/char/ftape/lowlevel/Makefile deleted file mode 100644 index febab07ba427..000000000000 --- a/drivers/char/ftape/lowlevel/Makefile +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | # | ||
2 | # Copyright (C) 1996, 1997 Clau-Justus Heine. | ||
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: /homes/cvs/ftape-stacked/ftape/lowlevel/Makefile,v $ | ||
19 | # $Revision: 1.4 $ | ||
20 | # $Date: 1997/10/07 09:26:02 $ | ||
21 | # | ||
22 | # Makefile for the lowlevel part QIC-40/80/3010/3020 floppy-tape | ||
23 | # driver for Linux. | ||
24 | # | ||
25 | |||
26 | obj-$(CONFIG_FTAPE) += ftape.o | ||
27 | |||
28 | ftape-objs := ftape-init.o fdc-io.o fdc-isr.o \ | ||
29 | ftape-bsm.o ftape-ctl.o ftape-read.o ftape-rw.o \ | ||
30 | ftape-write.o ftape-io.o ftape-calibr.o ftape-ecc.o fc-10.o \ | ||
31 | ftape-buffer.o ftape-format.o ftape_syms.o | ||
32 | |||
33 | ifeq ($(CONFIG_FTAPE),y) | ||
34 | ftape-objs += ftape-setup.o | ||
35 | endif | ||
36 | |||
37 | ifndef CONFIG_FT_NO_TRACE_AT_ALL | ||
38 | ftape-objs += ftape-tracing.o | ||
39 | endif | ||
40 | |||
41 | ifeq ($(CONFIG_FT_PROC_FS),y) | ||
42 | ftape-objs += ftape-proc.o | ||
43 | endif | ||
diff --git a/drivers/char/ftape/lowlevel/fc-10.c b/drivers/char/ftape/lowlevel/fc-10.c deleted file mode 100644 index 9bc1cddade76..000000000000 --- a/drivers/char/ftape/lowlevel/fc-10.c +++ /dev/null | |||
@@ -1,175 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | |||
4 | Copyright (C) 1993,1994 Jon Tombs. | ||
5 | |||
6 | This program is distributed in the hope that it will be useful, | ||
7 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | GNU General Public License for more details. | ||
10 | |||
11 | The entire guts of this program was written by dosemu, modified to | ||
12 | record reads and writes to the ports in the 0x180-0x188 address space, | ||
13 | while running the CMS program TAPE.EXE V2.0.5 supplied with the drive. | ||
14 | |||
15 | Modified to use an array of addresses and generally cleaned up (made | ||
16 | much shorter) 4 June 94, dosemu isn't that good at writing short code it | ||
17 | would seem :-). Made independent of 0x180, but I doubt it will work | ||
18 | at any other address. | ||
19 | |||
20 | Modified for distribution with ftape source. 21 June 94, SJL. | ||
21 | |||
22 | Modifications on 20 October 95, by Daniel Cohen (catman@wpi.edu): | ||
23 | Modified to support different DMA, IRQ, and IO Ports. Borland's | ||
24 | Turbo Debugger in virtual 8086 mode (TD386.EXE with hardware breakpoints | ||
25 | provided by the TDH386.SYS Device Driver) was used on the CMS program | ||
26 | TAPE V4.0.5. I set breakpoints on I/O to ports 0x180-0x187. Note that | ||
27 | CMS's program will not successfully configure the tape drive if you set | ||
28 | breakpoints on IO Reads, but you can set them on IO Writes without problems. | ||
29 | Known problems: | ||
30 | - You can not use DMA Channels 5 or 7. | ||
31 | |||
32 | Modification on 29 January 96, by Daniel Cohen (catman@wpi.edu): | ||
33 | Modified to only accept IRQs 3 - 7, or 9. Since we can only send a 3 bit | ||
34 | number representing the IRQ to the card, special handling is required when | ||
35 | IRQ 9 is selected. IRQ 2 and 9 are the same, and we should request IRQ 9 | ||
36 | from the kernel while telling the card to use IRQ 2. Thanks to Greg | ||
37 | Crider (gcrider@iclnet.org) for finding and locating this bug, as well as | ||
38 | testing the patch. | ||
39 | |||
40 | Modification on 11 December 96, by Claus Heine (claus@momo.math.rwth-aachen.de): | ||
41 | Modified a little to use variahle ft_fdc_base, ft_fdc_irq, ft_fdc_dma | ||
42 | instead of preprocessor symbols. Thus we can compile this into the module | ||
43 | or kernel and let the user specify the options as command line arguments. | ||
44 | |||
45 | * | ||
46 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.c,v $ | ||
47 | * $Revision: 1.2 $ | ||
48 | * $Date: 1997/10/05 19:18:04 $ | ||
49 | * | ||
50 | * This file contains code for the CMS FC-10/FC-20 card. | ||
51 | */ | ||
52 | |||
53 | #include <asm/io.h> | ||
54 | #include <linux/ftape.h> | ||
55 | #include "../lowlevel/ftape-tracing.h" | ||
56 | #include "../lowlevel/fdc-io.h" | ||
57 | #include "../lowlevel/fc-10.h" | ||
58 | |||
59 | static __u16 inbs_magic[] = { | ||
60 | 0x3, 0x3, 0x0, 0x4, 0x7, 0x2, 0x5, 0x3, 0x1, 0x4, | ||
61 | 0x3, 0x5, 0x2, 0x0, 0x3, 0x7, 0x4, 0x2, | ||
62 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 | ||
63 | }; | ||
64 | |||
65 | static __u16 fc10_ports[] = { | ||
66 | 0x180, 0x210, 0x2A0, 0x300, 0x330, 0x340, 0x370 | ||
67 | }; | ||
68 | |||
69 | int fc10_enable(void) | ||
70 | { | ||
71 | int i; | ||
72 | __u8 cardConfig = 0x00; | ||
73 | __u8 x; | ||
74 | TRACE_FUN(ft_t_flow); | ||
75 | |||
76 | /* This code will only work if the FC-10 (or FC-20) is set to | ||
77 | * use DMA channels 1, 2, or 3. DMA channels 5 and 7 seem to be | ||
78 | * initialized by the same command as channels 1 and 3, respectively. | ||
79 | */ | ||
80 | if (ft_fdc_dma > 3) { | ||
81 | TRACE_ABORT(0, ft_t_err, | ||
82 | "Error: The FC-10/20 must be set to use DMA channels 1, 2, or 3!"); | ||
83 | } | ||
84 | /* Only allow the FC-10/20 to use IRQ 3-7, or 9. Note that CMS's program | ||
85 | * only accepts IRQ's 2-7, but in linux, IRQ 2 is the same as IRQ 9. | ||
86 | */ | ||
87 | if (ft_fdc_irq < 3 || ft_fdc_irq == 8 || ft_fdc_irq > 9) { | ||
88 | TRACE_ABORT(0, ft_t_err, | ||
89 | "Error: The FC-10/20 must be set to use IRQ levels 3 - 7, or 9!\n" | ||
90 | KERN_INFO "Note: IRQ 9 is the same as IRQ 2"); | ||
91 | } | ||
92 | /* Clear state machine ??? | ||
93 | */ | ||
94 | for (i = 0; i < NR_ITEMS(inbs_magic); i++) { | ||
95 | inb(ft_fdc_base + inbs_magic[i]); | ||
96 | } | ||
97 | outb(0x0, ft_fdc_base); | ||
98 | |||
99 | x = inb(ft_fdc_base); | ||
100 | if (x == 0x13 || x == 0x93) { | ||
101 | for (i = 1; i < 8; i++) { | ||
102 | if (inb(ft_fdc_base + i) != x) { | ||
103 | TRACE_EXIT 0; | ||
104 | } | ||
105 | } | ||
106 | } else { | ||
107 | TRACE_EXIT 0; | ||
108 | } | ||
109 | |||
110 | outb(0x8, ft_fdc_base); | ||
111 | |||
112 | for (i = 0; i < 8; i++) { | ||
113 | if (inb(ft_fdc_base + i) != 0x0) { | ||
114 | TRACE_EXIT 0; | ||
115 | } | ||
116 | } | ||
117 | outb(0x10, ft_fdc_base); | ||
118 | |||
119 | for (i = 0; i < 8; i++) { | ||
120 | if (inb(ft_fdc_base + i) != 0xff) { | ||
121 | TRACE_EXIT 0; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | /* Okay, we found a FC-10 card ! ??? | ||
126 | */ | ||
127 | outb(0x0, fdc.ccr); | ||
128 | |||
129 | /* Clear state machine again ??? | ||
130 | */ | ||
131 | for (i = 0; i < NR_ITEMS(inbs_magic); i++) { | ||
132 | inb(ft_fdc_base + inbs_magic[i]); | ||
133 | } | ||
134 | /* Send io port */ | ||
135 | for (i = 0; i < NR_ITEMS(fc10_ports); i++) | ||
136 | if (ft_fdc_base == fc10_ports[i]) | ||
137 | cardConfig = i + 1; | ||
138 | if (cardConfig == 0) { | ||
139 | TRACE_EXIT 0; /* Invalid I/O Port */ | ||
140 | } | ||
141 | /* and IRQ - If using IRQ 9, tell the FC card it is actually IRQ 2 */ | ||
142 | if (ft_fdc_irq != 9) | ||
143 | cardConfig |= ft_fdc_irq << 3; | ||
144 | else | ||
145 | cardConfig |= 2 << 3; | ||
146 | |||
147 | /* and finally DMA Channel */ | ||
148 | cardConfig |= ft_fdc_dma << 6; | ||
149 | outb(cardConfig, ft_fdc_base); /* DMA [2 bits]/IRQ [3 bits]/BASE [3 bits] */ | ||
150 | |||
151 | /* Enable FC-10 ??? | ||
152 | */ | ||
153 | outb(0, fdc.ccr); | ||
154 | outb(0, fdc.dor2); | ||
155 | outb(FDC_DMA_MODE /* 8 */, fdc.dor); | ||
156 | outb(FDC_DMA_MODE /* 8 */, fdc.dor); | ||
157 | outb(1, fdc.dor2); | ||
158 | |||
159 | /************************************* | ||
160 | * | ||
161 | * cH: why the hell should this be necessary? This is done | ||
162 | * by fdc_reset()!!! | ||
163 | * | ||
164 | *************************************/ | ||
165 | /* Initialize fdc, select drive B: | ||
166 | */ | ||
167 | outb(FDC_DMA_MODE, fdc.dor); /* assert reset, dma & irq enabled */ | ||
168 | /* 0x08 */ | ||
169 | outb(FDC_DMA_MODE|FDC_RESET_NOT, fdc.dor); /* release reset */ | ||
170 | /* 0x08 | 0x04 = 0x0c */ | ||
171 | outb(FDC_DMA_MODE|FDC_RESET_NOT|FDC_MOTOR_1|FTAPE_SEL_B, fdc.dor); | ||
172 | /* 0x08 | 0x04 | 0x20 | 0x01 = 0x2d */ | ||
173 | /* select drive 1 */ /* why not drive 0 ???? */ | ||
174 | TRACE_EXIT (x == 0x93) ? 2 : 1; | ||
175 | } | ||
diff --git a/drivers/char/ftape/lowlevel/fc-10.h b/drivers/char/ftape/lowlevel/fc-10.h deleted file mode 100644 index da7b88bca889..000000000000 --- a/drivers/char/ftape/lowlevel/fc-10.h +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | #ifndef _FC_10_H | ||
2 | #define _FC_10_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1996 Bas Laarhoven. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.h,v $ | ||
23 | * $Revision: 1.1 $ | ||
24 | * $Date: 1997/09/19 09:05:22 $ | ||
25 | * | ||
26 | * This file contains definitions for the FC-10 code | ||
27 | * of the QIC-40/80 floppy-tape driver for Linux. | ||
28 | */ | ||
29 | |||
30 | /* | ||
31 | * fc-10.c defined global vars. | ||
32 | */ | ||
33 | |||
34 | /* | ||
35 | * fc-10.c defined global functions. | ||
36 | */ | ||
37 | extern int fc10_enable(void); | ||
38 | |||
39 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c deleted file mode 100644 index bbcf918f056f..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ /dev/null | |||
@@ -1,1349 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-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: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-io.c,v $ | ||
21 | * $Revision: 1.7.4.2 $ | ||
22 | * $Date: 1997/11/16 14:48:17 $ | ||
23 | * | ||
24 | * This file contains the low-level floppy disk interface code | ||
25 | * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for | ||
26 | * Linux. | ||
27 | */ | ||
28 | |||
29 | #include <linux/errno.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/ioport.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <asm/system.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/dma.h> | ||
37 | #include <asm/irq.h> | ||
38 | |||
39 | #include <linux/ftape.h> | ||
40 | #include <linux/qic117.h> | ||
41 | #include "../lowlevel/ftape-tracing.h" | ||
42 | #include "../lowlevel/fdc-io.h" | ||
43 | #include "../lowlevel/fdc-isr.h" | ||
44 | #include "../lowlevel/ftape-io.h" | ||
45 | #include "../lowlevel/ftape-rw.h" | ||
46 | #include "../lowlevel/ftape-ctl.h" | ||
47 | #include "../lowlevel/ftape-calibr.h" | ||
48 | #include "../lowlevel/fc-10.h" | ||
49 | |||
50 | /* Global vars. | ||
51 | */ | ||
52 | static int ftape_motor; | ||
53 | volatile int ftape_current_cylinder = -1; | ||
54 | volatile fdc_mode_enum fdc_mode = fdc_idle; | ||
55 | fdc_config_info fdc; | ||
56 | DECLARE_WAIT_QUEUE_HEAD(ftape_wait_intr); | ||
57 | |||
58 | unsigned int ft_fdc_base = CONFIG_FT_FDC_BASE; | ||
59 | unsigned int ft_fdc_irq = CONFIG_FT_FDC_IRQ; | ||
60 | unsigned int ft_fdc_dma = CONFIG_FT_FDC_DMA; | ||
61 | unsigned int ft_fdc_threshold = CONFIG_FT_FDC_THR; /* bytes */ | ||
62 | unsigned int ft_fdc_rate_limit = CONFIG_FT_FDC_MAX_RATE; /* bits/sec */ | ||
63 | int ft_probe_fc10 = CONFIG_FT_PROBE_FC10; | ||
64 | int ft_mach2 = CONFIG_FT_MACH2; | ||
65 | |||
66 | /* Local vars. | ||
67 | */ | ||
68 | static spinlock_t fdc_io_lock; | ||
69 | static unsigned int fdc_calibr_count; | ||
70 | static unsigned int fdc_calibr_time; | ||
71 | static int fdc_status; | ||
72 | volatile __u8 fdc_head; /* FDC head from sector id */ | ||
73 | volatile __u8 fdc_cyl; /* FDC track from sector id */ | ||
74 | volatile __u8 fdc_sect; /* FDC sector from sector id */ | ||
75 | static int fdc_data_rate = 500; /* data rate (Kbps) */ | ||
76 | static int fdc_rate_code; /* data rate code (0 == 500 Kbps) */ | ||
77 | static int fdc_seek_rate = 2; /* step rate (msec) */ | ||
78 | static void (*do_ftape) (void); | ||
79 | static int fdc_fifo_state; /* original fifo setting - fifo enabled */ | ||
80 | static int fdc_fifo_thr; /* original fifo setting - threshold */ | ||
81 | static int fdc_lock_state; /* original lock setting - locked */ | ||
82 | static int fdc_fifo_locked; /* has fifo && lock set ? */ | ||
83 | static __u8 fdc_precomp; /* default precomp. value (nsec) */ | ||
84 | static __u8 fdc_prec_code; /* fdc precomp. select code */ | ||
85 | |||
86 | static char ftape_id[] = "ftape"; /* used by request irq and free irq */ | ||
87 | |||
88 | static int fdc_set_seek_rate(int seek_rate); | ||
89 | |||
90 | void fdc_catch_stray_interrupts(int count) | ||
91 | { | ||
92 | unsigned long flags; | ||
93 | |||
94 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
95 | if (count == 0) { | ||
96 | ft_expected_stray_interrupts = 0; | ||
97 | } else { | ||
98 | ft_expected_stray_interrupts += count; | ||
99 | } | ||
100 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
101 | } | ||
102 | |||
103 | /* Wait during a timeout period for a given FDC status. | ||
104 | * If usecs == 0 then just test status, else wait at least for usecs. | ||
105 | * Returns -ETIME on timeout. Function must be calibrated first ! | ||
106 | */ | ||
107 | static int fdc_wait(unsigned int usecs, __u8 mask, __u8 state) | ||
108 | { | ||
109 | int count_1 = (fdc_calibr_count * usecs + | ||
110 | fdc_calibr_count - 1) / fdc_calibr_time; | ||
111 | |||
112 | do { | ||
113 | fdc_status = inb_p(fdc.msr); | ||
114 | if ((fdc_status & mask) == state) { | ||
115 | return 0; | ||
116 | } | ||
117 | } while (count_1-- >= 0); | ||
118 | return -ETIME; | ||
119 | } | ||
120 | |||
121 | int fdc_ready_wait(unsigned int usecs) | ||
122 | { | ||
123 | return fdc_wait(usecs, FDC_DATA_READY | FDC_BUSY, FDC_DATA_READY); | ||
124 | } | ||
125 | |||
126 | /* Why can't we just use udelay()? | ||
127 | */ | ||
128 | static void fdc_usec_wait(unsigned int usecs) | ||
129 | { | ||
130 | fdc_wait(usecs, 0, 1); /* will always timeout ! */ | ||
131 | } | ||
132 | |||
133 | static int fdc_ready_out_wait(unsigned int usecs) | ||
134 | { | ||
135 | fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ | ||
136 | return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_OUT_READY); | ||
137 | } | ||
138 | |||
139 | void fdc_wait_calibrate(void) | ||
140 | { | ||
141 | ftape_calibrate("fdc_wait", | ||
142 | fdc_usec_wait, &fdc_calibr_count, &fdc_calibr_time); | ||
143 | } | ||
144 | |||
145 | /* Wait for a (short) while for the FDC to become ready | ||
146 | * and transfer the next command byte. | ||
147 | * Return -ETIME on timeout on getting ready (depends on hardware!). | ||
148 | */ | ||
149 | static int fdc_write(const __u8 data) | ||
150 | { | ||
151 | fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ | ||
152 | if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_IN_READY) < 0) { | ||
153 | return -ETIME; | ||
154 | } else { | ||
155 | outb(data, fdc.fifo); | ||
156 | return 0; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | /* Wait for a (short) while for the FDC to become ready | ||
161 | * and transfer the next result byte. | ||
162 | * Return -ETIME if timeout on getting ready (depends on hardware!). | ||
163 | */ | ||
164 | static int fdc_read(__u8 * data) | ||
165 | { | ||
166 | fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ | ||
167 | if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_OUT_READY) < 0) { | ||
168 | return -ETIME; | ||
169 | } else { | ||
170 | *data = inb(fdc.fifo); | ||
171 | return 0; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | /* Output a cmd_len long command string to the FDC. | ||
176 | * The FDC should be ready to receive a new command or | ||
177 | * an error (EBUSY or ETIME) will occur. | ||
178 | */ | ||
179 | int fdc_command(const __u8 * cmd_data, int cmd_len) | ||
180 | { | ||
181 | int result = 0; | ||
182 | unsigned long flags; | ||
183 | int count = cmd_len; | ||
184 | int retry = 0; | ||
185 | #ifdef TESTING | ||
186 | static unsigned int last_time; | ||
187 | unsigned int time; | ||
188 | #endif | ||
189 | TRACE_FUN(ft_t_any); | ||
190 | |||
191 | fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ | ||
192 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
193 | if (!in_interrupt()) | ||
194 | /* Yes, I know, too much comments inside this function | ||
195 | * ... | ||
196 | * | ||
197 | * Yet another bug in the original driver. All that | ||
198 | * havoc is caused by the fact that the isr() sends | ||
199 | * itself a command to the floppy tape driver (pause, | ||
200 | * micro step pause). Now, the problem is that | ||
201 | * commands are transmitted via the fdc_seek | ||
202 | * command. But: the fdc performs seeks in the | ||
203 | * background i.e. it doesn't signal busy while | ||
204 | * sending the step pulses to the drive. Therefore the | ||
205 | * non-interrupt level driver has no chance to tell | ||
206 | * whether the isr() just has issued a seek. Therefore | ||
207 | * we HAVE TO have a look at the ft_hide_interrupt | ||
208 | * flag: it signals the non-interrupt level part of | ||
209 | * the driver that it has to wait for the fdc until it | ||
210 | * has completet seeking. | ||
211 | * | ||
212 | * THIS WAS PRESUMABLY THE REASON FOR ALL THAT | ||
213 | * "fdc_read timeout" errors, I HOPE :-) | ||
214 | */ | ||
215 | if (ft_hide_interrupt) { | ||
216 | restore_flags(flags); | ||
217 | TRACE(ft_t_info, | ||
218 | "Waiting for the isr() completing fdc_seek()"); | ||
219 | if (fdc_interrupt_wait(2 * FT_SECOND) < 0) { | ||
220 | TRACE(ft_t_warn, | ||
221 | "Warning: timeout waiting for isr() seek to complete"); | ||
222 | } | ||
223 | if (ft_hide_interrupt || !ft_seek_completed) { | ||
224 | /* There cannot be another | ||
225 | * interrupt. The isr() only stops | ||
226 | * the tape and the next interrupt | ||
227 | * won't come until we have send our | ||
228 | * command to the drive. | ||
229 | */ | ||
230 | TRACE_ABORT(-EIO, ft_t_bug, | ||
231 | "BUG? isr() is still seeking?\n" | ||
232 | KERN_INFO "hide: %d\n" | ||
233 | KERN_INFO "seek: %d", | ||
234 | ft_hide_interrupt, | ||
235 | ft_seek_completed); | ||
236 | |||
237 | } | ||
238 | fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ | ||
239 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
240 | } | ||
241 | fdc_status = inb(fdc.msr); | ||
242 | if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_IN_READY) { | ||
243 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
244 | TRACE_ABORT(-EBUSY, ft_t_err, "fdc not ready"); | ||
245 | } | ||
246 | fdc_mode = *cmd_data; /* used by isr */ | ||
247 | #ifdef TESTING | ||
248 | if (fdc_mode == FDC_SEEK) { | ||
249 | time = ftape_timediff(last_time, ftape_timestamp()); | ||
250 | if (time < 6000) { | ||
251 | TRACE(ft_t_bug,"Warning: short timeout between seek commands: %d", | ||
252 | time); | ||
253 | } | ||
254 | } | ||
255 | #endif | ||
256 | if (!in_interrupt()) { | ||
257 | /* shouldn't be cleared if called from isr | ||
258 | */ | ||
259 | ft_interrupt_seen = 0; | ||
260 | } | ||
261 | while (count) { | ||
262 | result = fdc_write(*cmd_data); | ||
263 | if (result < 0) { | ||
264 | TRACE(ft_t_fdc_dma, | ||
265 | "fdc_mode = %02x, status = %02x at index %d", | ||
266 | (int) fdc_mode, (int) fdc_status, | ||
267 | cmd_len - count); | ||
268 | if (++retry <= 3) { | ||
269 | TRACE(ft_t_warn, "fdc_write timeout, retry"); | ||
270 | } else { | ||
271 | TRACE(ft_t_err, "fdc_write timeout, fatal"); | ||
272 | /* recover ??? */ | ||
273 | break; | ||
274 | } | ||
275 | } else { | ||
276 | --count; | ||
277 | ++cmd_data; | ||
278 | } | ||
279 | } | ||
280 | #ifdef TESTING | ||
281 | if (fdc_mode == FDC_SEEK) { | ||
282 | last_time = ftape_timestamp(); | ||
283 | } | ||
284 | #endif | ||
285 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
286 | TRACE_EXIT result; | ||
287 | } | ||
288 | |||
289 | /* Input a res_len long result string from the FDC. | ||
290 | * The FDC should be ready to send the result or an error | ||
291 | * (EBUSY or ETIME) will occur. | ||
292 | */ | ||
293 | int fdc_result(__u8 * res_data, int res_len) | ||
294 | { | ||
295 | int result = 0; | ||
296 | unsigned long flags; | ||
297 | int count = res_len; | ||
298 | int retry = 0; | ||
299 | TRACE_FUN(ft_t_any); | ||
300 | |||
301 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
302 | fdc_status = inb(fdc.msr); | ||
303 | if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_OUT_READY) { | ||
304 | TRACE(ft_t_err, "fdc not ready"); | ||
305 | result = -EBUSY; | ||
306 | } else while (count) { | ||
307 | if (!(fdc_status & FDC_BUSY)) { | ||
308 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
309 | TRACE_ABORT(-EIO, ft_t_err, "premature end of result phase"); | ||
310 | } | ||
311 | result = fdc_read(res_data); | ||
312 | if (result < 0) { | ||
313 | TRACE(ft_t_fdc_dma, | ||
314 | "fdc_mode = %02x, status = %02x at index %d", | ||
315 | (int) fdc_mode, | ||
316 | (int) fdc_status, | ||
317 | res_len - count); | ||
318 | if (++retry <= 3) { | ||
319 | TRACE(ft_t_warn, "fdc_read timeout, retry"); | ||
320 | } else { | ||
321 | TRACE(ft_t_err, "fdc_read timeout, fatal"); | ||
322 | /* recover ??? */ | ||
323 | break; | ||
324 | ++retry; | ||
325 | } | ||
326 | } else { | ||
327 | --count; | ||
328 | ++res_data; | ||
329 | } | ||
330 | } | ||
331 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
332 | fdc_usec_wait(FT_RQM_DELAY); /* allow FDC to negate BSY */ | ||
333 | TRACE_EXIT result; | ||
334 | } | ||
335 | |||
336 | /* Handle command and result phases for | ||
337 | * commands without data phase. | ||
338 | */ | ||
339 | static int fdc_issue_command(const __u8 * out_data, int out_count, | ||
340 | __u8 * in_data, int in_count) | ||
341 | { | ||
342 | TRACE_FUN(ft_t_any); | ||
343 | |||
344 | if (out_count > 0) { | ||
345 | TRACE_CATCH(fdc_command(out_data, out_count),); | ||
346 | } | ||
347 | /* will take 24 - 30 usec for fdc_sense_drive_status and | ||
348 | * fdc_sense_interrupt_status commands. | ||
349 | * 35 fails sometimes (5/9/93 SJL) | ||
350 | * On a loaded system it incidentally takes longer than | ||
351 | * this for the fdc to get ready ! ?????? WHY ?????? | ||
352 | * So until we know what's going on use a very long timeout. | ||
353 | */ | ||
354 | TRACE_CATCH(fdc_ready_out_wait(500 /* usec */),); | ||
355 | if (in_count > 0) { | ||
356 | TRACE_CATCH(fdc_result(in_data, in_count), | ||
357 | TRACE(ft_t_err, "result phase aborted")); | ||
358 | } | ||
359 | TRACE_EXIT 0; | ||
360 | } | ||
361 | |||
362 | /* Wait for FDC interrupt with timeout (in milliseconds). | ||
363 | * Signals are blocked so the wait will not be aborted. | ||
364 | * Note: interrupts must be enabled ! (23/05/93 SJL) | ||
365 | */ | ||
366 | int fdc_interrupt_wait(unsigned int time) | ||
367 | { | ||
368 | DECLARE_WAITQUEUE(wait,current); | ||
369 | sigset_t old_sigmask; | ||
370 | static int resetting; | ||
371 | long timeout; | ||
372 | |||
373 | TRACE_FUN(ft_t_fdc_dma); | ||
374 | |||
375 | if (waitqueue_active(&ftape_wait_intr)) { | ||
376 | TRACE_ABORT(-EIO, ft_t_err, "error: nested call"); | ||
377 | } | ||
378 | /* timeout time will be up to USPT microseconds too long ! */ | ||
379 | timeout = (1000 * time + FT_USPT - 1) / FT_USPT; | ||
380 | |||
381 | spin_lock_irq(¤t->sighand->siglock); | ||
382 | old_sigmask = current->blocked; | ||
383 | sigfillset(¤t->blocked); | ||
384 | recalc_sigpending(); | ||
385 | spin_unlock_irq(¤t->sighand->siglock); | ||
386 | |||
387 | set_current_state(TASK_INTERRUPTIBLE); | ||
388 | add_wait_queue(&ftape_wait_intr, &wait); | ||
389 | while (!ft_interrupt_seen && timeout) | ||
390 | timeout = schedule_timeout_interruptible(timeout); | ||
391 | |||
392 | spin_lock_irq(¤t->sighand->siglock); | ||
393 | current->blocked = old_sigmask; | ||
394 | recalc_sigpending(); | ||
395 | spin_unlock_irq(¤t->sighand->siglock); | ||
396 | |||
397 | remove_wait_queue(&ftape_wait_intr, &wait); | ||
398 | /* the following IS necessary. True: as well | ||
399 | * wake_up_interruptible() as the schedule() set TASK_RUNNING | ||
400 | * when they wakeup a task, BUT: it may very well be that | ||
401 | * ft_interrupt_seen is already set to 1 when we enter here | ||
402 | * in which case schedule() gets never called, and | ||
403 | * TASK_RUNNING never set. This has the funny effect that we | ||
404 | * execute all the code until we leave kernel space, but then | ||
405 | * the task is stopped (a task CANNOT be preempted while in | ||
406 | * kernel mode. Sending a pair of SIGSTOP/SIGCONT to the | ||
407 | * tasks wakes it up again. Funny! :-) | ||
408 | */ | ||
409 | current->state = TASK_RUNNING; | ||
410 | if (ft_interrupt_seen) { /* woken up by interrupt */ | ||
411 | ft_interrupt_seen = 0; | ||
412 | TRACE_EXIT 0; | ||
413 | } | ||
414 | /* Original comment: | ||
415 | * In first instance, next statement seems unnecessary since | ||
416 | * it will be cleared in fdc_command. However, a small part of | ||
417 | * the software seems to rely on this being cleared here | ||
418 | * (ftape_close might fail) so stick to it until things get fixed ! | ||
419 | */ | ||
420 | /* My deeply sought of knowledge: | ||
421 | * Behold NO! It is obvious. fdc_reset() doesn't call fdc_command() | ||
422 | * but nevertheless uses fdc_interrupt_wait(). OF COURSE this needs to | ||
423 | * be reset here. | ||
424 | */ | ||
425 | ft_interrupt_seen = 0; /* clear for next call */ | ||
426 | if (!resetting) { | ||
427 | resetting = 1; /* break infinite recursion if reset fails */ | ||
428 | TRACE(ft_t_any, "cleanup reset"); | ||
429 | fdc_reset(); | ||
430 | resetting = 0; | ||
431 | } | ||
432 | TRACE_EXIT (signal_pending(current)) ? -EINTR : -ETIME; | ||
433 | } | ||
434 | |||
435 | /* Start/stop drive motor. Enable DMA mode. | ||
436 | */ | ||
437 | void fdc_motor(int motor) | ||
438 | { | ||
439 | int unit = ft_drive_sel; | ||
440 | int data = unit | FDC_RESET_NOT | FDC_DMA_MODE; | ||
441 | TRACE_FUN(ft_t_any); | ||
442 | |||
443 | ftape_motor = motor; | ||
444 | if (ftape_motor) { | ||
445 | data |= FDC_MOTOR_0 << unit; | ||
446 | TRACE(ft_t_noise, "turning motor %d on", unit); | ||
447 | } else { | ||
448 | TRACE(ft_t_noise, "turning motor %d off", unit); | ||
449 | } | ||
450 | if (ft_mach2) { | ||
451 | outb_p(data, fdc.dor2); | ||
452 | } else { | ||
453 | outb_p(data, fdc.dor); | ||
454 | } | ||
455 | ftape_sleep(10 * FT_MILLISECOND); | ||
456 | TRACE_EXIT; | ||
457 | } | ||
458 | |||
459 | static void fdc_update_dsr(void) | ||
460 | { | ||
461 | TRACE_FUN(ft_t_any); | ||
462 | |||
463 | TRACE(ft_t_flow, "rate = %d Kbps, precomp = %d ns", | ||
464 | fdc_data_rate, fdc_precomp); | ||
465 | if (fdc.type >= i82077) { | ||
466 | outb_p((fdc_rate_code & 0x03) | fdc_prec_code, fdc.dsr); | ||
467 | } else { | ||
468 | outb_p(fdc_rate_code & 0x03, fdc.ccr); | ||
469 | } | ||
470 | TRACE_EXIT; | ||
471 | } | ||
472 | |||
473 | void fdc_set_write_precomp(int precomp) | ||
474 | { | ||
475 | TRACE_FUN(ft_t_any); | ||
476 | |||
477 | TRACE(ft_t_noise, "New precomp: %d nsec", precomp); | ||
478 | fdc_precomp = precomp; | ||
479 | /* write precompensation can be set in multiples of 41.67 nsec. | ||
480 | * round the parameter to the nearest multiple and convert it | ||
481 | * into a fdc setting. Note that 0 means default to the fdc, | ||
482 | * 7 is used instead of that. | ||
483 | */ | ||
484 | fdc_prec_code = ((fdc_precomp + 21) / 42) << 2; | ||
485 | if (fdc_prec_code == 0 || fdc_prec_code > (6 << 2)) { | ||
486 | fdc_prec_code = 7 << 2; | ||
487 | } | ||
488 | fdc_update_dsr(); | ||
489 | TRACE_EXIT; | ||
490 | } | ||
491 | |||
492 | /* Reprogram the 82078 registers to use Data Rate Table 1 on all drives. | ||
493 | */ | ||
494 | static void fdc_set_drive_specs(void) | ||
495 | { | ||
496 | __u8 cmd[] = { FDC_DRIVE_SPEC, 0x00, 0x00, 0x00, 0x00, 0xc0}; | ||
497 | int result; | ||
498 | TRACE_FUN(ft_t_any); | ||
499 | |||
500 | TRACE(ft_t_flow, "Setting of drive specs called"); | ||
501 | if (fdc.type >= i82078_1) { | ||
502 | cmd[1] = (0 << 5) | (2 << 2); | ||
503 | cmd[2] = (1 << 5) | (2 << 2); | ||
504 | cmd[3] = (2 << 5) | (2 << 2); | ||
505 | cmd[4] = (3 << 5) | (2 << 2); | ||
506 | result = fdc_command(cmd, NR_ITEMS(cmd)); | ||
507 | if (result < 0) { | ||
508 | TRACE(ft_t_err, "Setting of drive specs failed"); | ||
509 | } | ||
510 | } | ||
511 | TRACE_EXIT; | ||
512 | } | ||
513 | |||
514 | /* Select clock for fdc, must correspond with tape drive setting ! | ||
515 | * This also influences the fdc timing so we must adjust some values. | ||
516 | */ | ||
517 | int fdc_set_data_rate(int rate) | ||
518 | { | ||
519 | int bad_rate = 0; | ||
520 | TRACE_FUN(ft_t_any); | ||
521 | |||
522 | /* Select clock for fdc, must correspond with tape drive setting ! | ||
523 | * This also influences the fdc timing so we must adjust some values. | ||
524 | */ | ||
525 | TRACE(ft_t_fdc_dma, "new rate = %d", rate); | ||
526 | switch (rate) { | ||
527 | case 250: | ||
528 | fdc_rate_code = fdc_data_rate_250; | ||
529 | break; | ||
530 | case 500: | ||
531 | fdc_rate_code = fdc_data_rate_500; | ||
532 | break; | ||
533 | case 1000: | ||
534 | if (fdc.type < i82077) { | ||
535 | bad_rate = 1; | ||
536 | } else { | ||
537 | fdc_rate_code = fdc_data_rate_1000; | ||
538 | } | ||
539 | break; | ||
540 | case 2000: | ||
541 | if (fdc.type < i82078_1) { | ||
542 | bad_rate = 1; | ||
543 | } else { | ||
544 | fdc_rate_code = fdc_data_rate_2000; | ||
545 | } | ||
546 | break; | ||
547 | default: | ||
548 | bad_rate = 1; | ||
549 | } | ||
550 | if (bad_rate) { | ||
551 | TRACE_ABORT(-EIO, | ||
552 | ft_t_fdc_dma, "%d is not a valid data rate", rate); | ||
553 | } | ||
554 | fdc_data_rate = rate; | ||
555 | fdc_update_dsr(); | ||
556 | fdc_set_seek_rate(fdc_seek_rate); /* clock changed! */ | ||
557 | ftape_udelay(1000); | ||
558 | TRACE_EXIT 0; | ||
559 | } | ||
560 | |||
561 | /* keep the unit select if keep_select is != 0, | ||
562 | */ | ||
563 | static void fdc_dor_reset(int keep_select) | ||
564 | { | ||
565 | __u8 fdc_ctl = ft_drive_sel; | ||
566 | |||
567 | if (keep_select != 0) { | ||
568 | fdc_ctl |= FDC_DMA_MODE; | ||
569 | if (ftape_motor) { | ||
570 | fdc_ctl |= FDC_MOTOR_0 << ft_drive_sel; | ||
571 | } | ||
572 | } | ||
573 | ftape_udelay(10); /* ??? but seems to be necessary */ | ||
574 | if (ft_mach2) { | ||
575 | outb_p(fdc_ctl & 0x0f, fdc.dor); | ||
576 | outb_p(fdc_ctl, fdc.dor2); | ||
577 | } else { | ||
578 | outb_p(fdc_ctl, fdc.dor); | ||
579 | } | ||
580 | fdc_usec_wait(10); /* delay >= 14 fdc clocks */ | ||
581 | if (keep_select == 0) { | ||
582 | fdc_ctl = 0; | ||
583 | } | ||
584 | fdc_ctl |= FDC_RESET_NOT; | ||
585 | if (ft_mach2) { | ||
586 | outb_p(fdc_ctl & 0x0f, fdc.dor); | ||
587 | outb_p(fdc_ctl, fdc.dor2); | ||
588 | } else { | ||
589 | outb_p(fdc_ctl, fdc.dor); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | /* Reset the floppy disk controller. Leave the ftape_unit selected. | ||
594 | */ | ||
595 | void fdc_reset(void) | ||
596 | { | ||
597 | int st0; | ||
598 | int i; | ||
599 | int dummy; | ||
600 | unsigned long flags; | ||
601 | TRACE_FUN(ft_t_any); | ||
602 | |||
603 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
604 | |||
605 | fdc_dor_reset(1); /* keep unit selected */ | ||
606 | |||
607 | fdc_mode = fdc_idle; | ||
608 | |||
609 | /* maybe the spin_lock_irq* pair is not necessary, BUT: | ||
610 | * the following line MUST be here. Otherwise fdc_interrupt_wait() | ||
611 | * won't wait. Note that fdc_reset() is called from | ||
612 | * ftape_dumb_stop() when the fdc is busy transferring data. In this | ||
613 | * case fdc_isr() MOST PROBABLY sets ft_interrupt_seen, and tries | ||
614 | * to get the result bytes from the fdc etc. CLASH. | ||
615 | */ | ||
616 | ft_interrupt_seen = 0; | ||
617 | |||
618 | /* Program data rate | ||
619 | */ | ||
620 | fdc_update_dsr(); /* restore data rate and precomp */ | ||
621 | |||
622 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
623 | |||
624 | /* | ||
625 | * Wait for first polling cycle to complete | ||
626 | */ | ||
627 | if (fdc_interrupt_wait(1 * FT_SECOND) < 0) { | ||
628 | TRACE(ft_t_err, "no drive polling interrupt!"); | ||
629 | } else { /* clear all disk-changed statuses */ | ||
630 | for (i = 0; i < 4; ++i) { | ||
631 | if(fdc_sense_interrupt_status(&st0, &dummy) != 0) { | ||
632 | TRACE(ft_t_err, "sense failed for %d", i); | ||
633 | } | ||
634 | if (i == ft_drive_sel) { | ||
635 | ftape_current_cylinder = dummy; | ||
636 | } | ||
637 | } | ||
638 | TRACE(ft_t_noise, "drive polling completed"); | ||
639 | } | ||
640 | /* | ||
641 | * SPECIFY COMMAND | ||
642 | */ | ||
643 | fdc_set_seek_rate(fdc_seek_rate); | ||
644 | /* | ||
645 | * DRIVE SPECIFICATION COMMAND (if fdc type known) | ||
646 | */ | ||
647 | if (fdc.type >= i82078_1) { | ||
648 | fdc_set_drive_specs(); | ||
649 | } | ||
650 | TRACE_EXIT; | ||
651 | } | ||
652 | |||
653 | #if !defined(CLK_48MHZ) | ||
654 | # define CLK_48MHZ 1 | ||
655 | #endif | ||
656 | |||
657 | /* When we're done, put the fdc into reset mode so that the regular | ||
658 | * floppy disk driver will figure out that something is wrong and | ||
659 | * initialize the controller the way it wants. | ||
660 | */ | ||
661 | void fdc_disable(void) | ||
662 | { | ||
663 | __u8 cmd1[] = {FDC_CONFIGURE, 0x00, 0x00, 0x00}; | ||
664 | __u8 cmd2[] = {FDC_LOCK}; | ||
665 | __u8 cmd3[] = {FDC_UNLOCK}; | ||
666 | __u8 stat[1]; | ||
667 | TRACE_FUN(ft_t_flow); | ||
668 | |||
669 | if (!fdc_fifo_locked) { | ||
670 | fdc_reset(); | ||
671 | TRACE_EXIT; | ||
672 | } | ||
673 | if (fdc_issue_command(cmd3, 1, stat, 1) < 0 || stat[0] != 0x00) { | ||
674 | fdc_dor_reset(0); | ||
675 | TRACE_ABORT(/**/, ft_t_bug, | ||
676 | "couldn't unlock fifo, configuration remains changed"); | ||
677 | } | ||
678 | fdc_fifo_locked = 0; | ||
679 | if (CLK_48MHZ && fdc.type >= i82078) { | ||
680 | cmd1[0] |= FDC_CLK48_BIT; | ||
681 | } | ||
682 | cmd1[2] = ((fdc_fifo_state) ? 0 : 0x20) + (fdc_fifo_thr - 1); | ||
683 | if (fdc_command(cmd1, NR_ITEMS(cmd1)) < 0) { | ||
684 | fdc_dor_reset(0); | ||
685 | TRACE_ABORT(/**/, ft_t_bug, | ||
686 | "couldn't reconfigure fifo to old state"); | ||
687 | } | ||
688 | if (fdc_lock_state && | ||
689 | fdc_issue_command(cmd2, 1, stat, 1) < 0) { | ||
690 | fdc_dor_reset(0); | ||
691 | TRACE_ABORT(/**/, ft_t_bug, "couldn't lock old state again"); | ||
692 | } | ||
693 | TRACE(ft_t_noise, "fifo restored: %sabled, thr. %d, %slocked", | ||
694 | fdc_fifo_state ? "en" : "dis", | ||
695 | fdc_fifo_thr, (fdc_lock_state) ? "" : "not "); | ||
696 | fdc_dor_reset(0); | ||
697 | TRACE_EXIT; | ||
698 | } | ||
699 | |||
700 | /* Specify FDC seek-rate (milliseconds) | ||
701 | */ | ||
702 | static int fdc_set_seek_rate(int seek_rate) | ||
703 | { | ||
704 | /* set step rate, dma mode, and minimal head load and unload times | ||
705 | */ | ||
706 | __u8 in[3] = { FDC_SPECIFY, 1, (1 << 1)}; | ||
707 | |||
708 | fdc_seek_rate = seek_rate; | ||
709 | in[1] |= (16 - (fdc_data_rate * fdc_seek_rate) / 500) << 4; | ||
710 | |||
711 | return fdc_command(in, 3); | ||
712 | } | ||
713 | |||
714 | /* Sense drive status: get unit's drive status (ST3) | ||
715 | */ | ||
716 | int fdc_sense_drive_status(int *st3) | ||
717 | { | ||
718 | __u8 out[2]; | ||
719 | __u8 in[1]; | ||
720 | TRACE_FUN(ft_t_any); | ||
721 | |||
722 | out[0] = FDC_SENSED; | ||
723 | out[1] = ft_drive_sel; | ||
724 | TRACE_CATCH(fdc_issue_command(out, 2, in, 1),); | ||
725 | *st3 = in[0]; | ||
726 | TRACE_EXIT 0; | ||
727 | } | ||
728 | |||
729 | /* Sense Interrupt Status command: | ||
730 | * should be issued at the end of each seek. | ||
731 | * get ST0 and current cylinder. | ||
732 | */ | ||
733 | int fdc_sense_interrupt_status(int *st0, int *current_cylinder) | ||
734 | { | ||
735 | __u8 out[1]; | ||
736 | __u8 in[2]; | ||
737 | TRACE_FUN(ft_t_any); | ||
738 | |||
739 | out[0] = FDC_SENSEI; | ||
740 | TRACE_CATCH(fdc_issue_command(out, 1, in, 2),); | ||
741 | *st0 = in[0]; | ||
742 | *current_cylinder = in[1]; | ||
743 | TRACE_EXIT 0; | ||
744 | } | ||
745 | |||
746 | /* step to track | ||
747 | */ | ||
748 | int fdc_seek(int track) | ||
749 | { | ||
750 | __u8 out[3]; | ||
751 | int st0, pcn; | ||
752 | #ifdef TESTING | ||
753 | unsigned int time; | ||
754 | #endif | ||
755 | TRACE_FUN(ft_t_any); | ||
756 | |||
757 | out[0] = FDC_SEEK; | ||
758 | out[1] = ft_drive_sel; | ||
759 | out[2] = track; | ||
760 | #ifdef TESTING | ||
761 | time = ftape_timestamp(); | ||
762 | #endif | ||
763 | /* We really need this command to work ! | ||
764 | */ | ||
765 | ft_seek_completed = 0; | ||
766 | TRACE_CATCH(fdc_command(out, 3), | ||
767 | fdc_reset(); | ||
768 | TRACE(ft_t_noise, "destination was: %d, resetting FDC...", | ||
769 | track)); | ||
770 | /* Handle interrupts until ft_seek_completed or timeout. | ||
771 | */ | ||
772 | for (;;) { | ||
773 | TRACE_CATCH(fdc_interrupt_wait(2 * FT_SECOND),); | ||
774 | if (ft_seek_completed) { | ||
775 | TRACE_CATCH(fdc_sense_interrupt_status(&st0, &pcn),); | ||
776 | if ((st0 & ST0_SEEK_END) == 0) { | ||
777 | TRACE_ABORT(-EIO, ft_t_err, | ||
778 | "no seek-end after seek completion !??"); | ||
779 | } | ||
780 | break; | ||
781 | } | ||
782 | } | ||
783 | #ifdef TESTING | ||
784 | time = ftape_timediff(time, ftape_timestamp()) / abs(track - ftape_current_cylinder); | ||
785 | if ((time < 900 || time > 3100) && abs(track - ftape_current_cylinder) > 5) { | ||
786 | TRACE(ft_t_warn, "Wrong FDC STEP interval: %d usecs (%d)", | ||
787 | time, track - ftape_current_cylinder); | ||
788 | } | ||
789 | #endif | ||
790 | /* Verify whether we issued the right tape command. | ||
791 | */ | ||
792 | /* Verify that we seek to the proper track. */ | ||
793 | if (pcn != track) { | ||
794 | TRACE_ABORT(-EIO, ft_t_err, "bad seek.."); | ||
795 | } | ||
796 | ftape_current_cylinder = track; | ||
797 | TRACE_EXIT 0; | ||
798 | } | ||
799 | |||
800 | static int perpend_mode; /* set if fdc is in perpendicular mode */ | ||
801 | |||
802 | static int perpend_off(void) | ||
803 | { | ||
804 | __u8 perpend[] = {FDC_PERPEND, 0x00}; | ||
805 | TRACE_FUN(ft_t_any); | ||
806 | |||
807 | if (perpend_mode) { | ||
808 | /* Turn off perpendicular mode */ | ||
809 | perpend[1] = 0x80; | ||
810 | TRACE_CATCH(fdc_command(perpend, 2), | ||
811 | TRACE(ft_t_err,"Perpendicular mode exit failed!")); | ||
812 | perpend_mode = 0; | ||
813 | } | ||
814 | TRACE_EXIT 0; | ||
815 | } | ||
816 | |||
817 | static int handle_perpend(int segment_id) | ||
818 | { | ||
819 | __u8 perpend[] = {FDC_PERPEND, 0x00}; | ||
820 | TRACE_FUN(ft_t_any); | ||
821 | |||
822 | /* When writing QIC-3020 tapes, turn on perpendicular mode | ||
823 | * if tape is moving in forward direction (even tracks). | ||
824 | */ | ||
825 | if (ft_qic_std == QIC_TAPE_QIC3020 && | ||
826 | ((segment_id / ft_segments_per_track) & 1) == 0) { | ||
827 | /* FIXME: some i82077 seem to support perpendicular mode as | ||
828 | * well. | ||
829 | */ | ||
830 | #if 0 | ||
831 | if (fdc.type < i82077AA) {} | ||
832 | #else | ||
833 | if (fdc.type < i82077 && ft_data_rate < 1000) { | ||
834 | #endif | ||
835 | /* fdc does not support perpendicular mode: complain | ||
836 | */ | ||
837 | TRACE_ABORT(-EIO, ft_t_err, | ||
838 | "Your FDC does not support QIC-3020."); | ||
839 | } | ||
840 | perpend[1] = 0x03 /* 0x83 + (0x4 << ft_drive_sel) */ ; | ||
841 | TRACE_CATCH(fdc_command(perpend, 2), | ||
842 | TRACE(ft_t_err,"Perpendicular mode entry failed!")); | ||
843 | TRACE(ft_t_flow, "Perpendicular mode set"); | ||
844 | perpend_mode = 1; | ||
845 | TRACE_EXIT 0; | ||
846 | } | ||
847 | TRACE_EXIT perpend_off(); | ||
848 | } | ||
849 | |||
850 | static inline void fdc_setup_dma(char mode, | ||
851 | volatile void *addr, unsigned int count) | ||
852 | { | ||
853 | /* Program the DMA controller. | ||
854 | */ | ||
855 | disable_dma(fdc.dma); | ||
856 | clear_dma_ff(fdc.dma); | ||
857 | set_dma_mode(fdc.dma, mode); | ||
858 | set_dma_addr(fdc.dma, virt_to_bus((void*)addr)); | ||
859 | set_dma_count(fdc.dma, count); | ||
860 | enable_dma(fdc.dma); | ||
861 | } | ||
862 | |||
863 | /* Setup fdc and dma for formatting the next segment | ||
864 | */ | ||
865 | int fdc_setup_formatting(buffer_struct * buff) | ||
866 | { | ||
867 | unsigned long flags; | ||
868 | __u8 out[6] = { | ||
869 | FDC_FORMAT, 0x00, 3, 4 * FT_SECTORS_PER_SEGMENT, 0x00, 0x6b | ||
870 | }; | ||
871 | TRACE_FUN(ft_t_any); | ||
872 | |||
873 | TRACE_CATCH(handle_perpend(buff->segment_id),); | ||
874 | /* Program the DMA controller. | ||
875 | */ | ||
876 | TRACE(ft_t_fdc_dma, | ||
877 | "phys. addr. = %lx", virt_to_bus((void*) buff->ptr)); | ||
878 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
879 | fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4); | ||
880 | /* Issue FDC command to start reading/writing. | ||
881 | */ | ||
882 | out[1] = ft_drive_sel; | ||
883 | out[4] = buff->gap3; | ||
884 | TRACE_CATCH(fdc_setup_error = fdc_command(out, sizeof(out)), | ||
885 | restore_flags(flags); fdc_mode = fdc_idle); | ||
886 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
887 | TRACE_EXIT 0; | ||
888 | } | ||
889 | |||
890 | |||
891 | /* Setup Floppy Disk Controller and DMA to read or write the next cluster | ||
892 | * of good sectors from or to the current segment. | ||
893 | */ | ||
894 | int fdc_setup_read_write(buffer_struct * buff, __u8 operation) | ||
895 | { | ||
896 | unsigned long flags; | ||
897 | __u8 out[9]; | ||
898 | int dma_mode; | ||
899 | TRACE_FUN(ft_t_any); | ||
900 | |||
901 | switch(operation) { | ||
902 | case FDC_VERIFY: | ||
903 | if (fdc.type < i82077) { | ||
904 | operation = FDC_READ; | ||
905 | } | ||
906 | case FDC_READ: | ||
907 | case FDC_READ_DELETED: | ||
908 | dma_mode = DMA_MODE_READ; | ||
909 | TRACE(ft_t_fdc_dma, "xfer %d sectors to 0x%p", | ||
910 | buff->sector_count, buff->ptr); | ||
911 | TRACE_CATCH(perpend_off(),); | ||
912 | break; | ||
913 | case FDC_WRITE_DELETED: | ||
914 | TRACE(ft_t_noise, "deleting segment %d", buff->segment_id); | ||
915 | case FDC_WRITE: | ||
916 | dma_mode = DMA_MODE_WRITE; | ||
917 | /* When writing QIC-3020 tapes, turn on perpendicular mode | ||
918 | * if tape is moving in forward direction (even tracks). | ||
919 | */ | ||
920 | TRACE_CATCH(handle_perpend(buff->segment_id),); | ||
921 | TRACE(ft_t_fdc_dma, "xfer %d sectors from 0x%p", | ||
922 | buff->sector_count, buff->ptr); | ||
923 | break; | ||
924 | default: | ||
925 | TRACE_ABORT(-EIO, | ||
926 | ft_t_bug, "bug: invalid operation parameter"); | ||
927 | } | ||
928 | TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr)); | ||
929 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
930 | if (operation != FDC_VERIFY) { | ||
931 | fdc_setup_dma(dma_mode, buff->ptr, | ||
932 | FT_SECTOR_SIZE * buff->sector_count); | ||
933 | } | ||
934 | /* Issue FDC command to start reading/writing. | ||
935 | */ | ||
936 | out[0] = operation; | ||
937 | out[1] = ft_drive_sel; | ||
938 | out[2] = buff->cyl; | ||
939 | out[3] = buff->head; | ||
940 | out[4] = buff->sect + buff->sector_offset; | ||
941 | out[5] = 3; /* Sector size of 1K. */ | ||
942 | out[6] = out[4] + buff->sector_count - 1; /* last sector */ | ||
943 | out[7] = 109; /* Gap length. */ | ||
944 | out[8] = 0xff; /* No limit to transfer size. */ | ||
945 | TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x", | ||
946 | out[2], out[3], out[4], out[6] - out[4] + 1); | ||
947 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
948 | TRACE_CATCH(fdc_setup_error = fdc_command(out, 9),fdc_mode = fdc_idle); | ||
949 | TRACE_EXIT 0; | ||
950 | } | ||
951 | |||
952 | int fdc_fifo_threshold(__u8 threshold, | ||
953 | int *fifo_state, int *lock_state, int *fifo_thr) | ||
954 | { | ||
955 | const __u8 cmd0[] = {FDC_DUMPREGS}; | ||
956 | __u8 cmd1[] = {FDC_CONFIGURE, 0, (0x0f & (threshold - 1)), 0}; | ||
957 | const __u8 cmd2[] = {FDC_LOCK}; | ||
958 | const __u8 cmd3[] = {FDC_UNLOCK}; | ||
959 | __u8 reg[10]; | ||
960 | __u8 stat; | ||
961 | int i; | ||
962 | int result; | ||
963 | TRACE_FUN(ft_t_any); | ||
964 | |||
965 | if (CLK_48MHZ && fdc.type >= i82078) { | ||
966 | cmd1[0] |= FDC_CLK48_BIT; | ||
967 | } | ||
968 | /* Dump fdc internal registers for examination | ||
969 | */ | ||
970 | TRACE_CATCH(fdc_command(cmd0, NR_ITEMS(cmd0)), | ||
971 | TRACE(ft_t_warn, "dumpreg cmd failed, fifo unchanged")); | ||
972 | /* Now read fdc internal registers from fifo | ||
973 | */ | ||
974 | for (i = 0; i < (int)NR_ITEMS(reg); ++i) { | ||
975 | fdc_read(®[i]); | ||
976 | TRACE(ft_t_fdc_dma, "Register %d = 0x%02x", i, reg[i]); | ||
977 | } | ||
978 | if (fifo_state && lock_state && fifo_thr) { | ||
979 | *fifo_state = (reg[8] & 0x20) == 0; | ||
980 | *lock_state = reg[7] & 0x80; | ||
981 | *fifo_thr = 1 + (reg[8] & 0x0f); | ||
982 | } | ||
983 | TRACE(ft_t_noise, | ||
984 | "original fifo state: %sabled, threshold %d, %slocked", | ||
985 | ((reg[8] & 0x20) == 0) ? "en" : "dis", | ||
986 | 1 + (reg[8] & 0x0f), (reg[7] & 0x80) ? "" : "not "); | ||
987 | /* If fdc is already locked, unlock it first ! */ | ||
988 | if (reg[7] & 0x80) { | ||
989 | fdc_ready_wait(100); | ||
990 | TRACE_CATCH(fdc_issue_command(cmd3, NR_ITEMS(cmd3), &stat, 1), | ||
991 | TRACE(ft_t_bug, "FDC unlock command failed, " | ||
992 | "configuration unchanged")); | ||
993 | } | ||
994 | fdc_fifo_locked = 0; | ||
995 | /* Enable fifo and set threshold at xx bytes to allow a | ||
996 | * reasonably large latency and reduce number of dma bursts. | ||
997 | */ | ||
998 | fdc_ready_wait(100); | ||
999 | if ((result = fdc_command(cmd1, NR_ITEMS(cmd1))) < 0) { | ||
1000 | TRACE(ft_t_bug, "configure cmd failed, fifo unchanged"); | ||
1001 | } | ||
1002 | /* Now lock configuration so reset will not change it | ||
1003 | */ | ||
1004 | if(fdc_issue_command(cmd2, NR_ITEMS(cmd2), &stat, 1) < 0 || | ||
1005 | stat != 0x10) { | ||
1006 | TRACE_ABORT(-EIO, ft_t_bug, | ||
1007 | "FDC lock command failed, stat = 0x%02x", stat); | ||
1008 | } | ||
1009 | fdc_fifo_locked = 1; | ||
1010 | TRACE_EXIT result; | ||
1011 | } | ||
1012 | |||
1013 | static int fdc_fifo_enable(void) | ||
1014 | { | ||
1015 | TRACE_FUN(ft_t_any); | ||
1016 | |||
1017 | if (fdc_fifo_locked) { | ||
1018 | TRACE_ABORT(0, ft_t_warn, "Fifo not enabled because locked"); | ||
1019 | } | ||
1020 | TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, | ||
1021 | &fdc_fifo_state, | ||
1022 | &fdc_lock_state, | ||
1023 | &fdc_fifo_thr),); | ||
1024 | TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, | ||
1025 | NULL, NULL, NULL),); | ||
1026 | TRACE_EXIT 0; | ||
1027 | } | ||
1028 | |||
1029 | /* Determine fd controller type | ||
1030 | */ | ||
1031 | static __u8 fdc_save_state[2]; | ||
1032 | |||
1033 | static int fdc_probe(void) | ||
1034 | { | ||
1035 | __u8 cmd[1]; | ||
1036 | __u8 stat[16]; /* must be able to hold dumpregs & save results */ | ||
1037 | int i; | ||
1038 | TRACE_FUN(ft_t_any); | ||
1039 | |||
1040 | /* Try to find out what kind of fd controller we have to deal with | ||
1041 | * Scheme borrowed from floppy driver: | ||
1042 | * first try if FDC_DUMPREGS command works | ||
1043 | * (this indicates that we have a 82072 or better) | ||
1044 | * then try the FDC_VERSION command (82072 doesn't support this) | ||
1045 | * then try the FDC_UNLOCK command (some older 82077's don't support this) | ||
1046 | * then try the FDC_PARTID command (82078's support this) | ||
1047 | */ | ||
1048 | cmd[0] = FDC_DUMPREGS; | ||
1049 | if (fdc_issue_command(cmd, 1, stat, 1) != 0) { | ||
1050 | TRACE_ABORT(no_fdc, ft_t_bug, "No FDC found"); | ||
1051 | } | ||
1052 | if (stat[0] == 0x80) { | ||
1053 | /* invalid command: must be pre 82072 */ | ||
1054 | TRACE_ABORT(i8272, | ||
1055 | ft_t_warn, "Type 8272A/765A compatible FDC found"); | ||
1056 | } | ||
1057 | fdc_result(&stat[1], 9); | ||
1058 | fdc_save_state[0] = stat[7]; | ||
1059 | fdc_save_state[1] = stat[8]; | ||
1060 | cmd[0] = FDC_VERSION; | ||
1061 | if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { | ||
1062 | TRACE_ABORT(i8272, ft_t_warn, "Type 82072 FDC found"); | ||
1063 | } | ||
1064 | if (*stat != 0x90) { | ||
1065 | TRACE_ABORT(i8272, ft_t_warn, "Unknown FDC found"); | ||
1066 | } | ||
1067 | cmd[0] = FDC_UNLOCK; | ||
1068 | if(fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] != 0x00) { | ||
1069 | TRACE_ABORT(i8272, ft_t_warn, | ||
1070 | "Type pre-1991 82077 FDC found, " | ||
1071 | "treating it like a 82072"); | ||
1072 | } | ||
1073 | if (fdc_save_state[0] & 0x80) { /* was locked */ | ||
1074 | cmd[0] = FDC_LOCK; /* restore lock */ | ||
1075 | (void)fdc_issue_command(cmd, 1, stat, 1); | ||
1076 | TRACE(ft_t_warn, "FDC is already locked"); | ||
1077 | } | ||
1078 | /* Test for a i82078 FDC */ | ||
1079 | cmd[0] = FDC_PARTID; | ||
1080 | if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { | ||
1081 | /* invalid command: not a i82078xx type FDC */ | ||
1082 | for (i = 0; i < 4; ++i) { | ||
1083 | outb_p(i, fdc.tdr); | ||
1084 | if ((inb_p(fdc.tdr) & 0x03) != i) { | ||
1085 | TRACE_ABORT(i82077, | ||
1086 | ft_t_warn, "Type 82077 FDC found"); | ||
1087 | } | ||
1088 | } | ||
1089 | TRACE_ABORT(i82077AA, ft_t_warn, "Type 82077AA FDC found"); | ||
1090 | } | ||
1091 | /* FDC_PARTID cmd succeeded */ | ||
1092 | switch (stat[0] >> 5) { | ||
1093 | case 0x0: | ||
1094 | /* i82078SL or i82078-1. The SL part cannot run at | ||
1095 | * 2Mbps (the SL and -1 dies are identical; they are | ||
1096 | * speed graded after production, according to Intel). | ||
1097 | * Some SL's can be detected by doing a SAVE cmd and | ||
1098 | * look at bit 7 of the first byte (the SEL3V# bit). | ||
1099 | * If it is 0, the part runs off 3Volts, and hence it | ||
1100 | * is a SL. | ||
1101 | */ | ||
1102 | cmd[0] = FDC_SAVE; | ||
1103 | if(fdc_issue_command(cmd, 1, stat, 16) < 0) { | ||
1104 | TRACE(ft_t_err, "FDC_SAVE failed. Dunno why"); | ||
1105 | /* guess we better claim the fdc to be a i82078 */ | ||
1106 | TRACE_ABORT(i82078, | ||
1107 | ft_t_warn, | ||
1108 | "Type i82078 FDC (i suppose) found"); | ||
1109 | } | ||
1110 | if ((stat[0] & FDC_SEL3V_BIT)) { | ||
1111 | /* fdc running off 5Volts; Pray that it's a i82078-1 | ||
1112 | */ | ||
1113 | TRACE_ABORT(i82078_1, ft_t_warn, | ||
1114 | "Type i82078-1 or 5Volt i82078SL FDC found"); | ||
1115 | } | ||
1116 | TRACE_ABORT(i82078, ft_t_warn, | ||
1117 | "Type 3Volt i82078SL FDC (1Mbps) found"); | ||
1118 | case 0x1: | ||
1119 | case 0x2: /* S82078B */ | ||
1120 | /* The '78B isn't '78 compatible. Detect it as a '77AA */ | ||
1121 | TRACE_ABORT(i82077AA, ft_t_warn, "Type i82077AA FDC found"); | ||
1122 | case 0x3: /* NSC PC8744 core; used in several super-IO chips */ | ||
1123 | TRACE_ABORT(i82077AA, | ||
1124 | ft_t_warn, "Type 82077AA compatible FDC found"); | ||
1125 | default: | ||
1126 | TRACE(ft_t_warn, "A previously undetected FDC found"); | ||
1127 | TRACE_ABORT(i82077AA, ft_t_warn, | ||
1128 | "Treating it as a 82077AA. Please report partid= %d", | ||
1129 | stat[0]); | ||
1130 | } /* switch(stat[ 0] >> 5) */ | ||
1131 | TRACE_EXIT no_fdc; | ||
1132 | } | ||
1133 | |||
1134 | static int fdc_request_regions(void) | ||
1135 | { | ||
1136 | TRACE_FUN(ft_t_flow); | ||
1137 | |||
1138 | if (ft_mach2 || ft_probe_fc10) { | ||
1139 | if (!request_region(fdc.sra, 8, "fdc (ft)")) { | ||
1140 | #ifndef BROKEN_FLOPPY_DRIVER | ||
1141 | TRACE_EXIT -EBUSY; | ||
1142 | #else | ||
1143 | TRACE(ft_t_warn, | ||
1144 | "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); | ||
1145 | #endif | ||
1146 | } | ||
1147 | } else { | ||
1148 | if (!request_region(fdc.sra, 6, "fdc (ft)")) { | ||
1149 | #ifndef BROKEN_FLOPPY_DRIVER | ||
1150 | TRACE_EXIT -EBUSY; | ||
1151 | #else | ||
1152 | TRACE(ft_t_warn, | ||
1153 | "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); | ||
1154 | #endif | ||
1155 | } | ||
1156 | if (!request_region(fdc.sra + 7, 1, "fdc (ft)")) { | ||
1157 | #ifndef BROKEN_FLOPPY_DRIVER | ||
1158 | release_region(fdc.sra, 6); | ||
1159 | TRACE_EXIT -EBUSY; | ||
1160 | #else | ||
1161 | TRACE(ft_t_warn, | ||
1162 | "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra + 7); | ||
1163 | #endif | ||
1164 | } | ||
1165 | } | ||
1166 | TRACE_EXIT 0; | ||
1167 | } | ||
1168 | |||
1169 | void fdc_release_regions(void) | ||
1170 | { | ||
1171 | TRACE_FUN(ft_t_flow); | ||
1172 | |||
1173 | if (fdc.sra != 0) { | ||
1174 | if (fdc.dor2 != 0) { | ||
1175 | release_region(fdc.sra, 8); | ||
1176 | } else { | ||
1177 | release_region(fdc.sra, 6); | ||
1178 | release_region(fdc.dir, 1); | ||
1179 | } | ||
1180 | } | ||
1181 | TRACE_EXIT; | ||
1182 | } | ||
1183 | |||
1184 | static int fdc_config_regs(unsigned int fdc_base, | ||
1185 | unsigned int fdc_irq, | ||
1186 | unsigned int fdc_dma) | ||
1187 | { | ||
1188 | TRACE_FUN(ft_t_flow); | ||
1189 | |||
1190 | fdc.irq = fdc_irq; | ||
1191 | fdc.dma = fdc_dma; | ||
1192 | fdc.sra = fdc_base; | ||
1193 | fdc.srb = fdc_base + 1; | ||
1194 | fdc.dor = fdc_base + 2; | ||
1195 | fdc.tdr = fdc_base + 3; | ||
1196 | fdc.msr = fdc.dsr = fdc_base + 4; | ||
1197 | fdc.fifo = fdc_base + 5; | ||
1198 | fdc.dir = fdc.ccr = fdc_base + 7; | ||
1199 | fdc.dor2 = (ft_mach2 || ft_probe_fc10) ? fdc_base + 6 : 0; | ||
1200 | TRACE_CATCH(fdc_request_regions(), fdc.sra = 0); | ||
1201 | TRACE_EXIT 0; | ||
1202 | } | ||
1203 | |||
1204 | static int fdc_config(void) | ||
1205 | { | ||
1206 | static int already_done; | ||
1207 | TRACE_FUN(ft_t_any); | ||
1208 | |||
1209 | if (already_done) { | ||
1210 | TRACE_CATCH(fdc_request_regions(),); | ||
1211 | *(fdc.hook) = fdc_isr; /* hook our handler in */ | ||
1212 | TRACE_EXIT 0; | ||
1213 | } | ||
1214 | if (ft_probe_fc10) { | ||
1215 | int fc_type; | ||
1216 | |||
1217 | TRACE_CATCH(fdc_config_regs(ft_fdc_base, | ||
1218 | ft_fdc_irq, ft_fdc_dma),); | ||
1219 | fc_type = fc10_enable(); | ||
1220 | if (fc_type != 0) { | ||
1221 | TRACE(ft_t_warn, "FC-%c0 controller found", '0' + fc_type); | ||
1222 | fdc.type = fc10; | ||
1223 | fdc.hook = &do_ftape; | ||
1224 | *(fdc.hook) = fdc_isr; /* hook our handler in */ | ||
1225 | already_done = 1; | ||
1226 | TRACE_EXIT 0; | ||
1227 | } else { | ||
1228 | TRACE(ft_t_warn, "FC-10/20 controller not found"); | ||
1229 | fdc_release_regions(); | ||
1230 | fdc.type = no_fdc; | ||
1231 | ft_probe_fc10 = 0; | ||
1232 | ft_fdc_base = 0x3f0; | ||
1233 | ft_fdc_irq = 6; | ||
1234 | ft_fdc_dma = 2; | ||
1235 | } | ||
1236 | } | ||
1237 | TRACE(ft_t_warn, "fdc base: 0x%x, irq: %d, dma: %d", | ||
1238 | ft_fdc_base, ft_fdc_irq, ft_fdc_dma); | ||
1239 | TRACE_CATCH(fdc_config_regs(ft_fdc_base, ft_fdc_irq, ft_fdc_dma),); | ||
1240 | fdc.hook = &do_ftape; | ||
1241 | *(fdc.hook) = fdc_isr; /* hook our handler in */ | ||
1242 | already_done = 1; | ||
1243 | TRACE_EXIT 0; | ||
1244 | } | ||
1245 | |||
1246 | static irqreturn_t ftape_interrupt(int irq, void *dev_id) | ||
1247 | { | ||
1248 | void (*handler) (void) = *fdc.hook; | ||
1249 | int handled = 0; | ||
1250 | TRACE_FUN(ft_t_any); | ||
1251 | |||
1252 | *fdc.hook = NULL; | ||
1253 | if (handler) { | ||
1254 | handled = 1; | ||
1255 | handler(); | ||
1256 | } else { | ||
1257 | TRACE(ft_t_bug, "Unexpected ftape interrupt"); | ||
1258 | } | ||
1259 | TRACE_EXIT IRQ_RETVAL(handled); | ||
1260 | } | ||
1261 | |||
1262 | static int fdc_grab_irq_and_dma(void) | ||
1263 | { | ||
1264 | TRACE_FUN(ft_t_any); | ||
1265 | |||
1266 | if (fdc.hook == &do_ftape) { | ||
1267 | /* Get fast interrupt handler. | ||
1268 | */ | ||
1269 | if (request_irq(fdc.irq, ftape_interrupt, | ||
1270 | IRQF_DISABLED, "ft", ftape_id)) { | ||
1271 | TRACE_ABORT(-EIO, ft_t_bug, | ||
1272 | "Unable to grab IRQ%d for ftape driver", | ||
1273 | fdc.irq); | ||
1274 | } | ||
1275 | if (request_dma(fdc.dma, ftape_id)) { | ||
1276 | free_irq(fdc.irq, ftape_id); | ||
1277 | TRACE_ABORT(-EIO, ft_t_bug, | ||
1278 | "Unable to grab DMA%d for ftape driver", | ||
1279 | fdc.dma); | ||
1280 | } | ||
1281 | } | ||
1282 | if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { | ||
1283 | /* Using same dma channel or irq as standard fdc, need | ||
1284 | * to disable the dma-gate on the std fdc. This | ||
1285 | * couldn't be done in the floppy driver as some | ||
1286 | * laptops are using the dma-gate to enter a low power | ||
1287 | * or even suspended state :-( | ||
1288 | */ | ||
1289 | outb_p(FDC_RESET_NOT, 0x3f2); | ||
1290 | TRACE(ft_t_noise, "DMA-gate on standard fdc disabled"); | ||
1291 | } | ||
1292 | TRACE_EXIT 0; | ||
1293 | } | ||
1294 | |||
1295 | int fdc_release_irq_and_dma(void) | ||
1296 | { | ||
1297 | TRACE_FUN(ft_t_any); | ||
1298 | |||
1299 | if (fdc.hook == &do_ftape) { | ||
1300 | disable_dma(fdc.dma); /* just in case... */ | ||
1301 | free_dma(fdc.dma); | ||
1302 | free_irq(fdc.irq, ftape_id); | ||
1303 | } | ||
1304 | if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { | ||
1305 | /* Using same dma channel as standard fdc, need to | ||
1306 | * disable the dma-gate on the std fdc. This couldn't | ||
1307 | * be done in the floppy driver as some laptops are | ||
1308 | * using the dma-gate to enter a low power or even | ||
1309 | * suspended state :-( | ||
1310 | */ | ||
1311 | outb_p(FDC_RESET_NOT | FDC_DMA_MODE, 0x3f2); | ||
1312 | TRACE(ft_t_noise, "DMA-gate on standard fdc enabled again"); | ||
1313 | } | ||
1314 | TRACE_EXIT 0; | ||
1315 | } | ||
1316 | |||
1317 | int fdc_init(void) | ||
1318 | { | ||
1319 | TRACE_FUN(ft_t_any); | ||
1320 | |||
1321 | /* find a FDC to use */ | ||
1322 | TRACE_CATCH(fdc_config(),); | ||
1323 | TRACE_CATCH(fdc_grab_irq_and_dma(), fdc_release_regions()); | ||
1324 | ftape_motor = 0; | ||
1325 | fdc_catch_stray_interrupts(0); /* clear number of awainted | ||
1326 | * stray interrupte | ||
1327 | */ | ||
1328 | fdc_catch_stray_interrupts(1); /* one always comes (?) */ | ||
1329 | TRACE(ft_t_flow, "resetting fdc"); | ||
1330 | fdc_set_seek_rate(2); /* use nominal QIC step rate */ | ||
1331 | fdc_reset(); /* init fdc & clear track counters */ | ||
1332 | if (fdc.type == no_fdc) { /* no FC-10 or FC-20 found */ | ||
1333 | fdc.type = fdc_probe(); | ||
1334 | fdc_reset(); /* update with new knowledge */ | ||
1335 | } | ||
1336 | if (fdc.type == no_fdc) { | ||
1337 | fdc_release_irq_and_dma(); | ||
1338 | fdc_release_regions(); | ||
1339 | TRACE_EXIT -ENXIO; | ||
1340 | } | ||
1341 | if (fdc.type >= i82077) { | ||
1342 | if (fdc_fifo_enable() < 0) { | ||
1343 | TRACE(ft_t_warn, "couldn't enable fdc fifo !"); | ||
1344 | } else { | ||
1345 | TRACE(ft_t_flow, "fdc fifo enabled and locked"); | ||
1346 | } | ||
1347 | } | ||
1348 | TRACE_EXIT 0; | ||
1349 | } | ||
diff --git a/drivers/char/ftape/lowlevel/fdc-io.h b/drivers/char/ftape/lowlevel/fdc-io.h deleted file mode 100644 index 7ec3c72178bb..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-io.h +++ /dev/null | |||
@@ -1,252 +0,0 @@ | |||
1 | #ifndef _FDC_IO_H | ||
2 | #define _FDC_IO_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-io.h,v $ | ||
24 | * $Revision: 1.3 $ | ||
25 | * $Date: 1997/10/05 19:18:06 $ | ||
26 | * | ||
27 | * This file contains the declarations for the low level | ||
28 | * functions that communicate with the floppy disk controller, | ||
29 | * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for | ||
30 | * Linux. | ||
31 | */ | ||
32 | |||
33 | #include <linux/fdreg.h> | ||
34 | |||
35 | #include "../lowlevel/ftape-bsm.h" | ||
36 | |||
37 | #define FDC_SK_BIT (0x20) | ||
38 | #define FDC_MT_BIT (0x80) | ||
39 | |||
40 | #define FDC_READ (FD_READ & ~(FDC_SK_BIT | FDC_MT_BIT)) | ||
41 | #define FDC_WRITE (FD_WRITE & ~FDC_MT_BIT) | ||
42 | #define FDC_READ_DELETED (0x4c) | ||
43 | #define FDC_WRITE_DELETED (0x49) | ||
44 | #define FDC_VERIFY (0x56) | ||
45 | #define FDC_READID (0x4a) | ||
46 | #define FDC_SENSED (0x04) | ||
47 | #define FDC_SENSEI (FD_SENSEI) | ||
48 | #define FDC_FORMAT (FD_FORMAT) | ||
49 | #define FDC_RECAL (FD_RECALIBRATE) | ||
50 | #define FDC_SEEK (FD_SEEK) | ||
51 | #define FDC_SPECIFY (FD_SPECIFY) | ||
52 | #define FDC_RECALIBR (FD_RECALIBRATE) | ||
53 | #define FDC_VERSION (FD_VERSION) | ||
54 | #define FDC_PERPEND (FD_PERPENDICULAR) | ||
55 | #define FDC_DUMPREGS (FD_DUMPREGS) | ||
56 | #define FDC_LOCK (FD_LOCK) | ||
57 | #define FDC_UNLOCK (FD_UNLOCK) | ||
58 | #define FDC_CONFIGURE (FD_CONFIGURE) | ||
59 | #define FDC_DRIVE_SPEC (0x8e) /* i82078 has this (any others?) */ | ||
60 | #define FDC_PARTID (0x18) /* i82078 has this */ | ||
61 | #define FDC_SAVE (0x2e) /* i82078 has this (any others?) */ | ||
62 | #define FDC_RESTORE (0x4e) /* i82078 has this (any others?) */ | ||
63 | |||
64 | #define FDC_STATUS_MASK (STATUS_BUSY | STATUS_DMA | STATUS_DIR | STATUS_READY) | ||
65 | #define FDC_DATA_READY (STATUS_READY) | ||
66 | #define FDC_DATA_OUTPUT (STATUS_DIR) | ||
67 | #define FDC_DATA_READY_MASK (STATUS_READY | STATUS_DIR) | ||
68 | #define FDC_DATA_OUT_READY (STATUS_READY | STATUS_DIR) | ||
69 | #define FDC_DATA_IN_READY (STATUS_READY) | ||
70 | #define FDC_BUSY (STATUS_BUSY) | ||
71 | #define FDC_CLK48_BIT (0x80) | ||
72 | #define FDC_SEL3V_BIT (0x40) | ||
73 | |||
74 | #define ST0_INT_MASK (ST0_INTR) | ||
75 | #define FDC_INT_NORMAL (ST0_INTR & 0x00) | ||
76 | #define FDC_INT_ABNORMAL (ST0_INTR & 0x40) | ||
77 | #define FDC_INT_INVALID (ST0_INTR & 0x80) | ||
78 | #define FDC_INT_READYCH (ST0_INTR & 0xC0) | ||
79 | #define ST0_SEEK_END (ST0_SE) | ||
80 | #define ST3_TRACK_0 (ST3_TZ) | ||
81 | |||
82 | #define FDC_RESET_NOT (0x04) | ||
83 | #define FDC_DMA_MODE (0x08) | ||
84 | #define FDC_MOTOR_0 (0x10) | ||
85 | #define FDC_MOTOR_1 (0x20) | ||
86 | |||
87 | typedef struct { | ||
88 | void (**hook) (void); /* our wedge into the isr */ | ||
89 | enum { | ||
90 | no_fdc, i8272, i82077, i82077AA, fc10, | ||
91 | i82078, i82078_1 | ||
92 | } type; /* FDC type */ | ||
93 | unsigned int irq; /* FDC irq nr */ | ||
94 | unsigned int dma; /* FDC dma channel nr */ | ||
95 | __u16 sra; /* Status register A (PS/2 only) */ | ||
96 | __u16 srb; /* Status register B (PS/2 only) */ | ||
97 | __u16 dor; /* Digital output register */ | ||
98 | __u16 tdr; /* Tape Drive Register (82077SL-1 & | ||
99 | 82078 only) */ | ||
100 | __u16 msr; /* Main Status Register */ | ||
101 | __u16 dsr; /* Datarate Select Register (8207x only) */ | ||
102 | __u16 fifo; /* Data register / Fifo on 8207x */ | ||
103 | __u16 dir; /* Digital Input Register */ | ||
104 | __u16 ccr; /* Configuration Control Register */ | ||
105 | __u16 dor2; /* Alternate dor on MACH-2 controller, | ||
106 | also used with FC-10, meaning unknown */ | ||
107 | } fdc_config_info; | ||
108 | |||
109 | typedef enum { | ||
110 | fdc_data_rate_250 = 2, | ||
111 | fdc_data_rate_300 = 1, /* any fdc in default configuration */ | ||
112 | fdc_data_rate_500 = 0, | ||
113 | fdc_data_rate_1000 = 3, | ||
114 | fdc_data_rate_2000 = 1, /* i82078-1: when using Data Rate Table #2 */ | ||
115 | } fdc_data_rate_type; | ||
116 | |||
117 | typedef enum { | ||
118 | fdc_idle = 0, | ||
119 | fdc_reading_data = FDC_READ, | ||
120 | fdc_seeking = FDC_SEEK, | ||
121 | fdc_writing_data = FDC_WRITE, | ||
122 | fdc_deleting = FDC_WRITE_DELETED, | ||
123 | fdc_reading_id = FDC_READID, | ||
124 | fdc_recalibrating = FDC_RECAL, | ||
125 | fdc_formatting = FDC_FORMAT, | ||
126 | fdc_verifying = FDC_VERIFY | ||
127 | } fdc_mode_enum; | ||
128 | |||
129 | typedef enum { | ||
130 | waiting = 0, | ||
131 | reading, | ||
132 | writing, | ||
133 | formatting, | ||
134 | verifying, | ||
135 | deleting, | ||
136 | done, | ||
137 | error, | ||
138 | mmapped, | ||
139 | } buffer_state_enum; | ||
140 | |||
141 | typedef struct { | ||
142 | __u8 *address; | ||
143 | volatile buffer_state_enum status; | ||
144 | volatile __u8 *ptr; | ||
145 | volatile unsigned int bytes; | ||
146 | volatile unsigned int segment_id; | ||
147 | |||
148 | /* bitmap for remainder of segment not yet handled. | ||
149 | * one bit set for each bad sector that must be skipped. | ||
150 | */ | ||
151 | volatile SectorMap bad_sector_map; | ||
152 | |||
153 | /* bitmap with bad data blocks in data buffer. | ||
154 | * the errors in this map may be retried. | ||
155 | */ | ||
156 | volatile SectorMap soft_error_map; | ||
157 | |||
158 | /* bitmap with bad data blocks in data buffer | ||
159 | * the errors in this map may not be retried. | ||
160 | */ | ||
161 | volatile SectorMap hard_error_map; | ||
162 | |||
163 | /* retry counter for soft errors. | ||
164 | */ | ||
165 | volatile int retry; | ||
166 | |||
167 | /* sectors to skip on retry ??? | ||
168 | */ | ||
169 | volatile unsigned int skip; | ||
170 | |||
171 | /* nr of data blocks in data buffer | ||
172 | */ | ||
173 | volatile unsigned int data_offset; | ||
174 | |||
175 | /* offset in segment for first sector to be handled. | ||
176 | */ | ||
177 | volatile unsigned int sector_offset; | ||
178 | |||
179 | /* size of cluster of good sectors to be handled. | ||
180 | */ | ||
181 | volatile unsigned int sector_count; | ||
182 | |||
183 | /* size of remaining part of segment to be handled. | ||
184 | */ | ||
185 | volatile unsigned int remaining; | ||
186 | |||
187 | /* points to next segment (contiguous) to be handled, | ||
188 | * or is zero if no read-ahead is allowed. | ||
189 | */ | ||
190 | volatile unsigned int next_segment; | ||
191 | |||
192 | /* flag being set if deleted data was read. | ||
193 | */ | ||
194 | volatile int deleted; | ||
195 | |||
196 | /* floppy coordinates of first sector in segment */ | ||
197 | volatile __u8 head; | ||
198 | volatile __u8 cyl; | ||
199 | volatile __u8 sect; | ||
200 | |||
201 | /* gap to use when formatting */ | ||
202 | __u8 gap3; | ||
203 | /* flag set when buffer is mmaped */ | ||
204 | int mmapped; | ||
205 | } buffer_struct; | ||
206 | |||
207 | /* | ||
208 | * fdc-io.c defined public variables | ||
209 | */ | ||
210 | extern volatile fdc_mode_enum fdc_mode; | ||
211 | extern int fdc_setup_error; /* outdated ??? */ | ||
212 | extern wait_queue_head_t ftape_wait_intr; | ||
213 | extern volatile int ftape_current_cylinder; /* track nr FDC thinks we're on */ | ||
214 | extern volatile __u8 fdc_head; /* FDC head */ | ||
215 | extern volatile __u8 fdc_cyl; /* FDC track */ | ||
216 | extern volatile __u8 fdc_sect; /* FDC sector */ | ||
217 | extern fdc_config_info fdc; /* FDC hardware configuration */ | ||
218 | |||
219 | extern unsigned int ft_fdc_base; | ||
220 | extern unsigned int ft_fdc_irq; | ||
221 | extern unsigned int ft_fdc_dma; | ||
222 | extern unsigned int ft_fdc_threshold; | ||
223 | extern unsigned int ft_fdc_rate_limit; | ||
224 | extern int ft_probe_fc10; | ||
225 | extern int ft_mach2; | ||
226 | /* | ||
227 | * fdc-io.c defined public functions | ||
228 | */ | ||
229 | extern void fdc_catch_stray_interrupts(int count); | ||
230 | extern int fdc_ready_wait(unsigned int timeout); | ||
231 | extern int fdc_command(const __u8 * cmd_data, int cmd_len); | ||
232 | extern int fdc_result(__u8 * res_data, int res_len); | ||
233 | extern int fdc_interrupt_wait(unsigned int time); | ||
234 | extern int fdc_seek(int track); | ||
235 | extern int fdc_sense_drive_status(int *st3); | ||
236 | extern void fdc_motor(int motor); | ||
237 | extern void fdc_reset(void); | ||
238 | extern void fdc_disable(void); | ||
239 | extern int fdc_fifo_threshold(__u8 threshold, | ||
240 | int *fifo_state, int *lock_state, int *fifo_thr); | ||
241 | extern void fdc_wait_calibrate(void); | ||
242 | extern int fdc_sense_interrupt_status(int *st0, int *current_cylinder); | ||
243 | extern void fdc_save_drive_specs(void); | ||
244 | extern void fdc_restore_drive_specs(void); | ||
245 | extern int fdc_set_data_rate(int rate); | ||
246 | extern void fdc_set_write_precomp(int precomp); | ||
247 | extern int fdc_release_irq_and_dma(void); | ||
248 | extern void fdc_release_regions(void); | ||
249 | extern int fdc_init(void); | ||
250 | extern int fdc_setup_read_write(buffer_struct * buff, __u8 operation); | ||
251 | extern int fdc_setup_formatting(buffer_struct * buff); | ||
252 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/fdc-isr.c b/drivers/char/ftape/lowlevel/fdc-isr.c deleted file mode 100644 index ad2bc733ae1b..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-isr.c +++ /dev/null | |||
@@ -1,1170 +0,0 @@ | |||
1 | /* | ||
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: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-isr.c,v $ | ||
21 | * $Revision: 1.9 $ | ||
22 | * $Date: 1997/10/17 23:01:53 $ | ||
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 | } else if (!waitqueue_active(&ftape_wait_intr)) { | ||
1123 | if (ft_expected_stray_interrupts == 0) { | ||
1124 | TRACE(ft_t_warn, "unexpected stray interrupt"); | ||
1125 | } else { | ||
1126 | TRACE(ft_t_flow, "expected stray interrupt"); | ||
1127 | --ft_expected_stray_interrupts; | ||
1128 | } | ||
1129 | } else { | ||
1130 | if (fdc_mode == fdc_reading_data || | ||
1131 | fdc_mode == fdc_verifying || | ||
1132 | fdc_mode == fdc_writing_data || | ||
1133 | fdc_mode == fdc_deleting || | ||
1134 | fdc_mode == fdc_formatting || | ||
1135 | fdc_mode == fdc_reading_id) { | ||
1136 | if (inb_p(fdc.msr) & FDC_BUSY) { | ||
1137 | TRACE(ft_t_bug, | ||
1138 | "***** FDC failure, busy too late"); | ||
1139 | } else { | ||
1140 | TRACE(ft_t_bug, | ||
1141 | "***** FDC failure, no busy"); | ||
1142 | } | ||
1143 | } else { | ||
1144 | TRACE(ft_t_fdc_dma, "awaited stray interrupt"); | ||
1145 | } | ||
1146 | } | ||
1147 | ft_hide_interrupt = 0; | ||
1148 | } | ||
1149 | /* Handle sleep code. | ||
1150 | */ | ||
1151 | if (!ft_hide_interrupt) { | ||
1152 | ft_interrupt_seen ++; | ||
1153 | if (waitqueue_active(&ftape_wait_intr)) { | ||
1154 | wake_up_interruptible(&ftape_wait_intr); | ||
1155 | } | ||
1156 | } else { | ||
1157 | TRACE(ft_t_flow, "hiding interrupt while %s", | ||
1158 | waitqueue_active(&ftape_wait_intr) ? "waiting":"active"); | ||
1159 | } | ||
1160 | #ifdef TESTING | ||
1161 | t0 = ftape_timediff(t0, ftape_timestamp()); | ||
1162 | if (t0 >= 1000) { | ||
1163 | /* only tell us about long calls */ | ||
1164 | TRACE(ft_t_noise, "isr() duration: %5d usec", t0); | ||
1165 | } | ||
1166 | #endif | ||
1167 | *fdc.hook = fdc_isr; /* hook our handler into the fdc code again */ | ||
1168 | --isr_active; | ||
1169 | TRACE_EXIT; | ||
1170 | } | ||
diff --git a/drivers/char/ftape/lowlevel/fdc-isr.h b/drivers/char/ftape/lowlevel/fdc-isr.h deleted file mode 100644 index 065aa978942d..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-isr.h +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | #ifndef _FDC_ISR_H | ||
2 | #define _FDC_ISR_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-isr.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:07 $ | ||
26 | * | ||
27 | * This file declares the global variables necessary to | ||
28 | * synchronize the interrupt service routine (isr) with the | ||
29 | * remainder of the QIC-40/80/3010/3020 floppy-tape driver | ||
30 | * "ftape" for Linux. | ||
31 | */ | ||
32 | |||
33 | /* | ||
34 | * fdc-isr.c defined public variables | ||
35 | */ | ||
36 | extern volatile int ft_expected_stray_interrupts; /* masks stray interrupts */ | ||
37 | extern volatile int ft_seek_completed; /* flag set by isr */ | ||
38 | extern volatile int ft_interrupt_seen; /* flag set by isr */ | ||
39 | extern volatile int ft_hide_interrupt; /* flag set by isr */ | ||
40 | |||
41 | /* | ||
42 | * fdc-io.c defined public functions | ||
43 | */ | ||
44 | extern void fdc_isr(void); | ||
45 | |||
46 | /* | ||
47 | * A kernel hook that steals one interrupt from the floppy | ||
48 | * driver (Should be fixed when the new fdc driver gets ready) | ||
49 | * See the linux kernel source files: | ||
50 | * drivers/block/floppy.c & drivers/block/blk.h | ||
51 | * for the details. | ||
52 | */ | ||
53 | extern void (*do_floppy) (void); | ||
54 | |||
55 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.c b/drivers/char/ftape/lowlevel/ftape-bsm.c deleted file mode 100644 index d1a301cc344f..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-bsm.c +++ /dev/null | |||
@@ -1,491 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1994-1996 Bas Laarhoven, | ||
3 | * (C) 1996-1997 Claus 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: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-bsm.c,v $ | ||
21 | * $Revision: 1.3 $ | ||
22 | * $Date: 1997/10/05 19:15:15 $ | ||
23 | * | ||
24 | * This file contains the bad-sector map handling code for | ||
25 | * the QIC-117 floppy tape driver for Linux. | ||
26 | * QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented. | ||
27 | */ | ||
28 | |||
29 | #include <linux/string.h> | ||
30 | |||
31 | #include <linux/ftape.h> | ||
32 | #include "../lowlevel/ftape-tracing.h" | ||
33 | #include "../lowlevel/ftape-bsm.h" | ||
34 | #include "../lowlevel/ftape-ctl.h" | ||
35 | #include "../lowlevel/ftape-rw.h" | ||
36 | |||
37 | /* Global vars. | ||
38 | */ | ||
39 | |||
40 | /* Local vars. | ||
41 | */ | ||
42 | static __u8 *bad_sector_map; | ||
43 | static SectorCount *bsm_hash_ptr; | ||
44 | |||
45 | typedef enum { | ||
46 | forward, backward | ||
47 | } mode_type; | ||
48 | |||
49 | #if 0 | ||
50 | static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map); | ||
51 | #endif | ||
52 | |||
53 | #if 0 | ||
54 | /* fix_tape converts a normal QIC-80 tape into a 'wide' tape. | ||
55 | * For testing purposes only ! | ||
56 | */ | ||
57 | void fix_tape(__u8 * buffer, ft_format_type new_code) | ||
58 | { | ||
59 | static __u8 list[BAD_SECTOR_MAP_SIZE]; | ||
60 | SectorMap *src_ptr = (SectorMap *) list; | ||
61 | __u8 *dst_ptr = bad_sector_map; | ||
62 | SectorMap map; | ||
63 | unsigned int sector = 1; | ||
64 | int i; | ||
65 | |||
66 | if (format_code != fmt_var && format_code != fmt_big) { | ||
67 | memcpy(list, bad_sector_map, sizeof(list)); | ||
68 | memset(bad_sector_map, 0, sizeof(bad_sector_map)); | ||
69 | while ((__u8 *) src_ptr - list < sizeof(list)) { | ||
70 | map = *src_ptr++; | ||
71 | if (map == EMPTY_SEGMENT) { | ||
72 | *(SectorMap *) dst_ptr = 0x800000 + sector; | ||
73 | dst_ptr += 3; | ||
74 | sector += SECTORS_PER_SEGMENT; | ||
75 | } else { | ||
76 | for (i = 0; i < SECTORS_PER_SEGMENT; ++i) { | ||
77 | if (map & 1) { | ||
78 | *(SewctorMap *) dst_ptr = sector; | ||
79 | dst_ptr += 3; | ||
80 | } | ||
81 | map >>= 1; | ||
82 | ++sector; | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | bad_sector_map_changed = 1; | ||
88 | *(buffer + 4) = new_code; /* put new format code */ | ||
89 | if (format_code != fmt_var && new_code == fmt_big) { | ||
90 | PUT4(buffer, FT_6_HSEG_1, (__u32)GET2(buffer, 6)); | ||
91 | PUT4(buffer, FT_6_HSEG_2, (__u32)GET2(buffer, 8)); | ||
92 | PUT4(buffer, FT_6_FRST_SEG, (__u32)GET2(buffer, 10)); | ||
93 | PUT4(buffer, FT_6_LAST_SEG, (__u32)GET2(buffer, 12)); | ||
94 | memset(buffer+6, '\0', 8); | ||
95 | } | ||
96 | format_code = new_code; | ||
97 | } | ||
98 | |||
99 | #endif | ||
100 | |||
101 | /* given buffer that contains a header segment, find the end of | ||
102 | * of the bsm list | ||
103 | */ | ||
104 | __u8 * ftape_find_end_of_bsm_list(__u8 * address) | ||
105 | { | ||
106 | __u8 *ptr = address + FT_HEADER_END; /* start of bsm list */ | ||
107 | __u8 *limit = address + FT_SEGMENT_SIZE; | ||
108 | while (ptr + 2 < limit) { | ||
109 | if (ptr[0] || ptr[1] || ptr[2]) { | ||
110 | ptr += 3; | ||
111 | } else { | ||
112 | return ptr; | ||
113 | } | ||
114 | } | ||
115 | return NULL; | ||
116 | } | ||
117 | |||
118 | static inline void put_sector(SectorCount *ptr, unsigned int sector) | ||
119 | { | ||
120 | ptr->bytes[0] = sector & 0xff; | ||
121 | sector >>= 8; | ||
122 | ptr->bytes[1] = sector & 0xff; | ||
123 | sector >>= 8; | ||
124 | ptr->bytes[2] = sector & 0xff; | ||
125 | } | ||
126 | |||
127 | static inline unsigned int get_sector(SectorCount *ptr) | ||
128 | { | ||
129 | #if 1 | ||
130 | unsigned int sector; | ||
131 | |||
132 | sector = ptr->bytes[0]; | ||
133 | sector += ptr->bytes[1] << 8; | ||
134 | sector += ptr->bytes[2] << 16; | ||
135 | |||
136 | return sector; | ||
137 | #else | ||
138 | /* GET4 gets the next four bytes in Intel little endian order | ||
139 | * and converts them to host byte order and handles unaligned | ||
140 | * access. | ||
141 | */ | ||
142 | return (GET4(ptr, 0) & 0x00ffffff); /* back to host byte order */ | ||
143 | #endif | ||
144 | } | ||
145 | |||
146 | static void bsm_debug_fake(void) | ||
147 | { | ||
148 | /* for testing of bad sector handling at end of tape | ||
149 | */ | ||
150 | #if 0 | ||
151 | ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 3, | ||
152 | 0x000003e0; | ||
153 | ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 2, | ||
154 | 0xff3fffff; | ||
155 | ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 1, | ||
156 | 0xffffe000; | ||
157 | #endif | ||
158 | /* Enable to test bad sector handling | ||
159 | */ | ||
160 | #if 0 | ||
161 | ftape_put_bad_sector_entry(30, 0xfffffffe) | ||
162 | ftape_put_bad_sector_entry(32, 0x7fffffff); | ||
163 | ftape_put_bad_sector_entry(34, 0xfffeffff); | ||
164 | ftape_put_bad_sector_entry(36, 0x55555555); | ||
165 | ftape_put_bad_sector_entry(38, 0xffffffff); | ||
166 | ftape_put_bad_sector_entry(50, 0xffff0000); | ||
167 | ftape_put_bad_sector_entry(51, 0xffffffff); | ||
168 | ftape_put_bad_sector_entry(52, 0xffffffff); | ||
169 | ftape_put_bad_sector_entry(53, 0x0000ffff); | ||
170 | #endif | ||
171 | /* Enable when testing multiple volume tar dumps. | ||
172 | */ | ||
173 | #if 0 | ||
174 | { | ||
175 | int i; | ||
176 | |||
177 | for (i = ft_first_data_segment; | ||
178 | i <= ft_last_data_segment - 7; ++i) { | ||
179 | ftape_put_bad_sector_entry(i, EMPTY_SEGMENT); | ||
180 | } | ||
181 | } | ||
182 | #endif | ||
183 | /* Enable when testing bit positions in *_error_map | ||
184 | */ | ||
185 | #if 0 | ||
186 | { | ||
187 | int i; | ||
188 | |||
189 | for (i = first_data_segment; i <= last_data_segment; ++i) { | ||
190 | ftape_put_bad_sector_entry(i, | ||
191 | ftape_get_bad_sector_entry(i) | ||
192 | | 0x00ff00ff); | ||
193 | } | ||
194 | } | ||
195 | #endif | ||
196 | } | ||
197 | |||
198 | static void print_bad_sector_map(void) | ||
199 | { | ||
200 | unsigned int good_sectors; | ||
201 | unsigned int total_bad = 0; | ||
202 | int i; | ||
203 | TRACE_FUN(ft_t_flow); | ||
204 | |||
205 | if (ft_format_code == fmt_big || | ||
206 | ft_format_code == fmt_var || | ||
207 | ft_format_code == fmt_1100ft) { | ||
208 | SectorCount *ptr = (SectorCount *)bad_sector_map; | ||
209 | unsigned int sector; | ||
210 | __u16 *ptr16; | ||
211 | |||
212 | while((sector = get_sector(ptr++)) != 0) { | ||
213 | if ((ft_format_code == fmt_big || | ||
214 | ft_format_code == fmt_var) && | ||
215 | sector & 0x800000) { | ||
216 | total_bad += FT_SECTORS_PER_SEGMENT - 3; | ||
217 | TRACE(ft_t_noise, "bad segment at sector: %6d", | ||
218 | sector & 0x7fffff); | ||
219 | } else { | ||
220 | ++total_bad; | ||
221 | TRACE(ft_t_noise, "bad sector: %6d", sector); | ||
222 | } | ||
223 | } | ||
224 | /* Display old ftape's end-of-file marks | ||
225 | */ | ||
226 | ptr16 = (__u16*)ptr; | ||
227 | while ((sector = get_unaligned(ptr16++)) != 0) { | ||
228 | TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d", | ||
229 | sector, get_unaligned(ptr16++)); | ||
230 | } | ||
231 | } else { /* fixed size format */ | ||
232 | for (i = ft_first_data_segment; | ||
233 | i < (int)(ft_segments_per_track * ft_tracks_per_tape); ++i) { | ||
234 | SectorMap map = ((SectorMap *) bad_sector_map)[i]; | ||
235 | |||
236 | if (map) { | ||
237 | TRACE(ft_t_noise, | ||
238 | "bsm for segment %4d: 0x%08x", i, (unsigned int)map); | ||
239 | total_bad += ((map == EMPTY_SEGMENT) | ||
240 | ? FT_SECTORS_PER_SEGMENT - 3 | ||
241 | : count_ones(map)); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | good_sectors = | ||
246 | ((ft_segments_per_track * ft_tracks_per_tape - ft_first_data_segment) | ||
247 | * (FT_SECTORS_PER_SEGMENT - 3)) - total_bad; | ||
248 | TRACE(ft_t_info, "%d Kb usable on this tape", good_sectors); | ||
249 | if (total_bad == 0) { | ||
250 | TRACE(ft_t_info, | ||
251 | "WARNING: this tape has no bad blocks registered !"); | ||
252 | } else { | ||
253 | TRACE(ft_t_info, "%d bad sectors", total_bad); | ||
254 | } | ||
255 | TRACE_EXIT; | ||
256 | } | ||
257 | |||
258 | |||
259 | void ftape_extract_bad_sector_map(__u8 * buffer) | ||
260 | { | ||
261 | TRACE_FUN(ft_t_any); | ||
262 | |||
263 | /* Fill the bad sector map with the contents of buffer. | ||
264 | */ | ||
265 | if (ft_format_code == fmt_var || ft_format_code == fmt_big) { | ||
266 | /* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed | ||
267 | * sector log but use this area to extend the bad sector map. | ||
268 | */ | ||
269 | bad_sector_map = &buffer[FT_HEADER_END]; | ||
270 | } else { | ||
271 | /* non-wide QIC-80 tapes have a failed sector log area that | ||
272 | * mustn't be included in the bad sector map. | ||
273 | */ | ||
274 | bad_sector_map = &buffer[FT_FSL + FT_FSL_SIZE]; | ||
275 | } | ||
276 | if (ft_format_code == fmt_1100ft || | ||
277 | ft_format_code == fmt_var || | ||
278 | ft_format_code == fmt_big) { | ||
279 | bsm_hash_ptr = (SectorCount *)bad_sector_map; | ||
280 | } else { | ||
281 | bsm_hash_ptr = NULL; | ||
282 | } | ||
283 | bsm_debug_fake(); | ||
284 | if (TRACE_LEVEL >= ft_t_info) { | ||
285 | print_bad_sector_map(); | ||
286 | } | ||
287 | TRACE_EXIT; | ||
288 | } | ||
289 | |||
290 | static inline SectorMap cvt2map(unsigned int sector) | ||
291 | { | ||
292 | return 1 << (((sector & 0x7fffff) - 1) % FT_SECTORS_PER_SEGMENT); | ||
293 | } | ||
294 | |||
295 | static inline int cvt2segment(unsigned int sector) | ||
296 | { | ||
297 | return ((sector & 0x7fffff) - 1) / FT_SECTORS_PER_SEGMENT; | ||
298 | } | ||
299 | |||
300 | static int forward_seek_entry(int segment_id, | ||
301 | SectorCount **ptr, | ||
302 | SectorMap *map) | ||
303 | { | ||
304 | unsigned int sector; | ||
305 | int segment; | ||
306 | |||
307 | do { | ||
308 | sector = get_sector((*ptr)++); | ||
309 | segment = cvt2segment(sector); | ||
310 | } while (sector != 0 && segment < segment_id); | ||
311 | (*ptr) --; /* point to first sector >= segment_id */ | ||
312 | /* Get all sectors in segment_id | ||
313 | */ | ||
314 | if (sector == 0 || segment != segment_id) { | ||
315 | *map = 0; | ||
316 | return 0; | ||
317 | } else if ((sector & 0x800000) && | ||
318 | (ft_format_code == fmt_var || ft_format_code == fmt_big)) { | ||
319 | *map = EMPTY_SEGMENT; | ||
320 | return FT_SECTORS_PER_SEGMENT; | ||
321 | } else { | ||
322 | int count = 1; | ||
323 | SectorCount *tmp_ptr = (*ptr) + 1; | ||
324 | |||
325 | *map = cvt2map(sector); | ||
326 | while ((sector = get_sector(tmp_ptr++)) != 0 && | ||
327 | (segment = cvt2segment(sector)) == segment_id) { | ||
328 | *map |= cvt2map(sector); | ||
329 | ++count; | ||
330 | } | ||
331 | return count; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | static int backwards_seek_entry(int segment_id, | ||
336 | SectorCount **ptr, | ||
337 | SectorMap *map) | ||
338 | { | ||
339 | unsigned int sector; | ||
340 | int segment; /* max unsigned int */ | ||
341 | |||
342 | if (*ptr <= (SectorCount *)bad_sector_map) { | ||
343 | *map = 0; | ||
344 | return 0; | ||
345 | } | ||
346 | do { | ||
347 | sector = get_sector(--(*ptr)); | ||
348 | segment = cvt2segment(sector); | ||
349 | } while (*ptr > (SectorCount *)bad_sector_map && segment > segment_id); | ||
350 | if (segment > segment_id) { /* at start of list, no entry found */ | ||
351 | *map = 0; | ||
352 | return 0; | ||
353 | } else if (segment < segment_id) { | ||
354 | /* before smaller entry, adjust for overshoot */ | ||
355 | (*ptr) ++; | ||
356 | *map = 0; | ||
357 | return 0; | ||
358 | } else if ((sector & 0x800000) && | ||
359 | (ft_format_code == fmt_big || ft_format_code == fmt_var)) { | ||
360 | *map = EMPTY_SEGMENT; | ||
361 | return FT_SECTORS_PER_SEGMENT; | ||
362 | } else { /* get all sectors in segment_id */ | ||
363 | int count = 1; | ||
364 | |||
365 | *map = cvt2map(sector); | ||
366 | while(*ptr > (SectorCount *)bad_sector_map) { | ||
367 | sector = get_sector(--(*ptr)); | ||
368 | segment = cvt2segment(sector); | ||
369 | if (segment != segment_id) { | ||
370 | break; | ||
371 | } | ||
372 | *map |= cvt2map(sector); | ||
373 | ++count; | ||
374 | } | ||
375 | if (segment < segment_id) { | ||
376 | (*ptr) ++; | ||
377 | } | ||
378 | return count; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | #if 0 | ||
383 | static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map) | ||
384 | { | ||
385 | SectorCount *ptr = (SectorCount *)bad_sector_map; | ||
386 | int count; | ||
387 | int new_count; | ||
388 | SectorMap map; | ||
389 | TRACE_FUN(ft_t_any); | ||
390 | |||
391 | if (ft_format_code == fmt_1100ft || | ||
392 | ft_format_code == fmt_var || | ||
393 | ft_format_code == fmt_big) { | ||
394 | count = forward_seek_entry(segment_id, &ptr, &map); | ||
395 | new_count = count_ones(new_map); | ||
396 | /* If format code == 4 put empty segment instead of 32 | ||
397 | * bad sectors. | ||
398 | */ | ||
399 | if (ft_format_code == fmt_var || ft_format_code == fmt_big) { | ||
400 | if (new_count == FT_SECTORS_PER_SEGMENT) { | ||
401 | new_count = 1; | ||
402 | } | ||
403 | if (count == FT_SECTORS_PER_SEGMENT) { | ||
404 | count = 1; | ||
405 | } | ||
406 | } | ||
407 | if (count != new_count) { | ||
408 | /* insert (or delete if < 0) new_count - count | ||
409 | * entries. Move trailing part of list | ||
410 | * including terminating 0. | ||
411 | */ | ||
412 | SectorCount *hi_ptr = ptr; | ||
413 | |||
414 | do { | ||
415 | } while (get_sector(hi_ptr++) != 0); | ||
416 | /* Note: ptr is of type byte *, and each bad sector | ||
417 | * consumes 3 bytes. | ||
418 | */ | ||
419 | memmove(ptr + new_count, ptr + count, | ||
420 | (size_t)(hi_ptr - (ptr + count))*sizeof(SectorCount)); | ||
421 | } | ||
422 | TRACE(ft_t_noise, "putting map 0x%08x at %p, segment %d", | ||
423 | (unsigned int)new_map, ptr, segment_id); | ||
424 | if (new_count == 1 && new_map == EMPTY_SEGMENT) { | ||
425 | put_sector(ptr++, (0x800001 + | ||
426 | segment_id * | ||
427 | FT_SECTORS_PER_SEGMENT)); | ||
428 | } else { | ||
429 | int i = 0; | ||
430 | |||
431 | while (new_map) { | ||
432 | if (new_map & 1) { | ||
433 | put_sector(ptr++, | ||
434 | 1 + segment_id * | ||
435 | FT_SECTORS_PER_SEGMENT + i); | ||
436 | } | ||
437 | ++i; | ||
438 | new_map >>= 1; | ||
439 | } | ||
440 | } | ||
441 | } else { | ||
442 | ((SectorMap *) bad_sector_map)[segment_id] = new_map; | ||
443 | } | ||
444 | TRACE_EXIT; | ||
445 | } | ||
446 | #endif /* 0 */ | ||
447 | |||
448 | SectorMap ftape_get_bad_sector_entry(int segment_id) | ||
449 | { | ||
450 | if (ft_used_header_segment == -1) { | ||
451 | /* When reading header segment we'll need a blank map. | ||
452 | */ | ||
453 | return 0; | ||
454 | } else if (bsm_hash_ptr != NULL) { | ||
455 | /* Invariants: | ||
456 | * map - mask value returned on last call. | ||
457 | * bsm_hash_ptr - points to first sector greater or equal to | ||
458 | * first sector in last_referenced segment. | ||
459 | * last_referenced - segment id used in the last call, | ||
460 | * sector and map belong to this id. | ||
461 | * This code is designed for sequential access and retries. | ||
462 | * For true random access it may have to be redesigned. | ||
463 | */ | ||
464 | static int last_reference = -1; | ||
465 | static SectorMap map; | ||
466 | |||
467 | if (segment_id > last_reference) { | ||
468 | /* Skip all sectors before segment_id | ||
469 | */ | ||
470 | forward_seek_entry(segment_id, &bsm_hash_ptr, &map); | ||
471 | } else if (segment_id < last_reference) { | ||
472 | /* Skip backwards until begin of buffer or | ||
473 | * first sector in segment_id | ||
474 | */ | ||
475 | backwards_seek_entry(segment_id, &bsm_hash_ptr, &map); | ||
476 | } /* segment_id == last_reference : keep map */ | ||
477 | last_reference = segment_id; | ||
478 | return map; | ||
479 | } else { | ||
480 | return ((SectorMap *) bad_sector_map)[segment_id]; | ||
481 | } | ||
482 | } | ||
483 | |||
484 | /* This is simply here to prevent us from overwriting other kernel | ||
485 | * data. Writes will result in NULL Pointer dereference. | ||
486 | */ | ||
487 | void ftape_init_bsm(void) | ||
488 | { | ||
489 | bad_sector_map = NULL; | ||
490 | bsm_hash_ptr = NULL; | ||
491 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.h b/drivers/char/ftape/lowlevel/ftape-bsm.h deleted file mode 100644 index ed45465af4d4..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-bsm.h +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | #ifndef _FTAPE_BSM_H | ||
2 | #define _FTAPE_BSM_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-bsm.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:07 $ | ||
26 | * | ||
27 | * This file contains definitions for the bad sector map handling | ||
28 | * routines for the QIC-117 floppy-tape driver for Linux. | ||
29 | */ | ||
30 | |||
31 | #include <linux/ftape.h> | ||
32 | #include <linux/ftape-header-segment.h> | ||
33 | |||
34 | #define EMPTY_SEGMENT (0xffffffff) | ||
35 | #define FAKE_SEGMENT (0xfffffffe) | ||
36 | |||
37 | /* maximum (format code 4) bad sector map size (bytes). | ||
38 | */ | ||
39 | #define BAD_SECTOR_MAP_SIZE (29 * SECTOR_SIZE - 256) | ||
40 | |||
41 | /* format code 4 bad sector entry, ftape uses this | ||
42 | * internally for all format codes | ||
43 | */ | ||
44 | typedef __u32 SectorMap; | ||
45 | /* variable and 1100 ft bad sector map entry. These three bytes represent | ||
46 | * a single sector address measured from BOT. | ||
47 | */ | ||
48 | typedef struct NewSectorMap { | ||
49 | __u8 bytes[3]; | ||
50 | } SectorCount; | ||
51 | |||
52 | |||
53 | /* | ||
54 | * ftape-bsm.c defined global vars. | ||
55 | */ | ||
56 | |||
57 | /* | ||
58 | * ftape-bsm.c defined global functions. | ||
59 | */ | ||
60 | extern void update_bad_sector_map(__u8 * buffer); | ||
61 | extern void ftape_extract_bad_sector_map(__u8 * buffer); | ||
62 | extern SectorMap ftape_get_bad_sector_entry(int segment_id); | ||
63 | extern __u8 *ftape_find_end_of_bsm_list(__u8 * address); | ||
64 | extern void ftape_init_bsm(void); | ||
65 | |||
66 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.c b/drivers/char/ftape/lowlevel/ftape-buffer.c deleted file mode 100644 index c706ff162771..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-buffer.c +++ /dev/null | |||
@@ -1,130 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1997 Claus-Justus Heine | ||
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 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-buffer.c,v $ | ||
20 | * $Revision: 1.3 $ | ||
21 | * $Date: 1997/10/16 23:33:11 $ | ||
22 | * | ||
23 | * This file contains the allocator/dealloctor for ftape's dynamic dma | ||
24 | * buffer. | ||
25 | */ | ||
26 | |||
27 | #include <linux/slab.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/mman.h> | ||
30 | #include <asm/dma.h> | ||
31 | |||
32 | #include <linux/ftape.h> | ||
33 | #include "../lowlevel/ftape-rw.h" | ||
34 | #include "../lowlevel/ftape-read.h" | ||
35 | #include "../lowlevel/ftape-tracing.h" | ||
36 | #include "../lowlevel/ftape-buffer.h" | ||
37 | |||
38 | /* DMA'able memory allocation stuff. | ||
39 | */ | ||
40 | |||
41 | static inline void *dmaalloc(size_t size) | ||
42 | { | ||
43 | unsigned long addr; | ||
44 | |||
45 | if (size == 0) { | ||
46 | return NULL; | ||
47 | } | ||
48 | addr = __get_dma_pages(GFP_KERNEL, get_order(size)); | ||
49 | if (addr) { | ||
50 | struct page *page; | ||
51 | |||
52 | for (page = virt_to_page(addr); page < virt_to_page(addr+size); page++) | ||
53 | SetPageReserved(page); | ||
54 | } | ||
55 | return (void *)addr; | ||
56 | } | ||
57 | |||
58 | static inline void dmafree(void *addr, size_t size) | ||
59 | { | ||
60 | if (size > 0) { | ||
61 | struct page *page; | ||
62 | |||
63 | for (page = virt_to_page((unsigned long)addr); | ||
64 | page < virt_to_page((unsigned long)addr+size); page++) | ||
65 | ClearPageReserved(page); | ||
66 | free_pages((unsigned long) addr, get_order(size)); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static int add_one_buffer(void) | ||
71 | { | ||
72 | TRACE_FUN(ft_t_flow); | ||
73 | |||
74 | if (ft_nr_buffers >= FT_MAX_NR_BUFFERS) { | ||
75 | TRACE_EXIT -ENOMEM; | ||
76 | } | ||
77 | ft_buffer[ft_nr_buffers] = kmalloc(sizeof(buffer_struct), GFP_KERNEL); | ||
78 | if (ft_buffer[ft_nr_buffers] == NULL) { | ||
79 | TRACE_EXIT -ENOMEM; | ||
80 | } | ||
81 | memset(ft_buffer[ft_nr_buffers], 0, sizeof(buffer_struct)); | ||
82 | ft_buffer[ft_nr_buffers]->address = dmaalloc(FT_BUFF_SIZE); | ||
83 | if (ft_buffer[ft_nr_buffers]->address == NULL) { | ||
84 | kfree(ft_buffer[ft_nr_buffers]); | ||
85 | ft_buffer[ft_nr_buffers] = NULL; | ||
86 | TRACE_EXIT -ENOMEM; | ||
87 | } | ||
88 | ft_nr_buffers ++; | ||
89 | TRACE(ft_t_info, "buffer nr #%d @ %p, dma area @ %p", | ||
90 | ft_nr_buffers, | ||
91 | ft_buffer[ft_nr_buffers-1], | ||
92 | ft_buffer[ft_nr_buffers-1]->address); | ||
93 | TRACE_EXIT 0; | ||
94 | } | ||
95 | |||
96 | static void del_one_buffer(void) | ||
97 | { | ||
98 | TRACE_FUN(ft_t_flow); | ||
99 | if (ft_nr_buffers > 0) { | ||
100 | TRACE(ft_t_info, "releasing buffer nr #%d @ %p, dma area @ %p", | ||
101 | ft_nr_buffers, | ||
102 | ft_buffer[ft_nr_buffers-1], | ||
103 | ft_buffer[ft_nr_buffers-1]->address); | ||
104 | ft_nr_buffers --; | ||
105 | dmafree(ft_buffer[ft_nr_buffers]->address, FT_BUFF_SIZE); | ||
106 | kfree(ft_buffer[ft_nr_buffers]); | ||
107 | ft_buffer[ft_nr_buffers] = NULL; | ||
108 | } | ||
109 | TRACE_EXIT; | ||
110 | } | ||
111 | |||
112 | int ftape_set_nr_buffers(int cnt) | ||
113 | { | ||
114 | int delta = cnt - ft_nr_buffers; | ||
115 | TRACE_FUN(ft_t_flow); | ||
116 | |||
117 | if (delta > 0) { | ||
118 | while (delta--) { | ||
119 | if (add_one_buffer() < 0) { | ||
120 | TRACE_EXIT -ENOMEM; | ||
121 | } | ||
122 | } | ||
123 | } else if (delta < 0) { | ||
124 | while (delta++) { | ||
125 | del_one_buffer(); | ||
126 | } | ||
127 | } | ||
128 | ftape_zap_read_buffers(); | ||
129 | TRACE_EXIT 0; | ||
130 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.h b/drivers/char/ftape/lowlevel/ftape-buffer.h deleted file mode 100644 index eec99cee8f82..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-buffer.h +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | #ifndef _FTAPE_BUFFER_H | ||
2 | #define _FTAPE_BUFFER_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1997 Claus-Justus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-buffer.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:18:08 $ | ||
25 | * | ||
26 | * This file contains the allocator/dealloctor for ftape's dynamic dma | ||
27 | * buffer. | ||
28 | */ | ||
29 | |||
30 | extern int ftape_set_nr_buffers(int cnt); | ||
31 | |||
32 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c deleted file mode 100644 index 8e50bfd35a52..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-calibr.c +++ /dev/null | |||
@@ -1,275 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 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 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-calibr.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:18:08 $ | ||
22 | * | ||
23 | * GP calibration routine for processor speed dependent | ||
24 | * functions. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/jiffies.h> | ||
29 | #include <asm/system.h> | ||
30 | #include <asm/io.h> | ||
31 | #if defined(__alpha__) | ||
32 | # include <asm/hwrpb.h> | ||
33 | #elif defined(__x86_64__) | ||
34 | # include <asm/msr.h> | ||
35 | # include <asm/timex.h> | ||
36 | #elif defined(__i386__) | ||
37 | # include <linux/timex.h> | ||
38 | #endif | ||
39 | #include <linux/ftape.h> | ||
40 | #include "../lowlevel/ftape-tracing.h" | ||
41 | #include "../lowlevel/ftape-calibr.h" | ||
42 | #include "../lowlevel/fdc-io.h" | ||
43 | |||
44 | #undef DEBUG | ||
45 | |||
46 | #if !defined(__alpha__) && !defined(__i386__) && !defined(__x86_64__) | ||
47 | # error Ftape is not implemented for this architecture! | ||
48 | #endif | ||
49 | |||
50 | #if defined(__alpha__) || defined(__x86_64__) | ||
51 | static unsigned long ps_per_cycle = 0; | ||
52 | #endif | ||
53 | |||
54 | static spinlock_t calibr_lock; | ||
55 | |||
56 | /* | ||
57 | * Note: On Intel PCs, the clock ticks at 100 Hz (HZ==100) which is | ||
58 | * too slow for certain timeouts (and that clock doesn't even tick | ||
59 | * when interrupts are disabled). For that reason, the 8254 timer is | ||
60 | * used directly to implement fine-grained timeouts. However, on | ||
61 | * Alpha PCs, the 8254 is *not* used to implement the clock tick | ||
62 | * (which is 1024 Hz, normally) and the 8254 timer runs at some | ||
63 | * "random" frequency (it seems to run at 18Hz, but it's not safe to | ||
64 | * rely on this value). Instead, we use the Alpha's "rpcc" | ||
65 | * instruction to read cycle counts. As this is a 32 bit counter, | ||
66 | * it will overflow only once per 30 seconds (on a 200MHz machine), | ||
67 | * which is plenty. | ||
68 | */ | ||
69 | |||
70 | unsigned int ftape_timestamp(void) | ||
71 | { | ||
72 | #if defined(__alpha__) | ||
73 | unsigned long r; | ||
74 | |||
75 | asm volatile ("rpcc %0" : "=r" (r)); | ||
76 | return r; | ||
77 | #elif defined(__x86_64__) | ||
78 | unsigned long r; | ||
79 | rdtscl(r); | ||
80 | return r; | ||
81 | #elif defined(__i386__) | ||
82 | |||
83 | /* | ||
84 | * Note that there is some time between counter underflowing and jiffies | ||
85 | * increasing, so the code below won't always give correct output. | ||
86 | * -Vojtech | ||
87 | */ | ||
88 | |||
89 | unsigned long flags; | ||
90 | __u16 lo; | ||
91 | __u16 hi; | ||
92 | |||
93 | spin_lock_irqsave(&calibr_lock, flags); | ||
94 | outb_p(0x00, 0x43); /* latch the count ASAP */ | ||
95 | lo = inb_p(0x40); /* read the latched count */ | ||
96 | lo |= inb(0x40) << 8; | ||
97 | hi = jiffies; | ||
98 | spin_unlock_irqrestore(&calibr_lock, flags); | ||
99 | return ((hi + 1) * (unsigned int) LATCH) - lo; /* downcounter ! */ | ||
100 | #endif | ||
101 | } | ||
102 | |||
103 | static unsigned int short_ftape_timestamp(void) | ||
104 | { | ||
105 | #if defined(__alpha__) || defined(__x86_64__) | ||
106 | return ftape_timestamp(); | ||
107 | #elif defined(__i386__) | ||
108 | unsigned int count; | ||
109 | unsigned long flags; | ||
110 | |||
111 | spin_lock_irqsave(&calibr_lock, flags); | ||
112 | outb_p(0x00, 0x43); /* latch the count ASAP */ | ||
113 | count = inb_p(0x40); /* read the latched count */ | ||
114 | count |= inb(0x40) << 8; | ||
115 | spin_unlock_irqrestore(&calibr_lock, flags); | ||
116 | return (LATCH - count); /* normal: downcounter */ | ||
117 | #endif | ||
118 | } | ||
119 | |||
120 | static unsigned int diff(unsigned int t0, unsigned int t1) | ||
121 | { | ||
122 | #if defined(__alpha__) || defined(__x86_64__) | ||
123 | return (t1 - t0); | ||
124 | #elif defined(__i386__) | ||
125 | /* | ||
126 | * This is tricky: to work for both short and full ftape_timestamps | ||
127 | * we'll have to discriminate between these. | ||
128 | * If it _looks_ like short stamps with wrapping around we'll | ||
129 | * asume it are. This will generate a small error if it really | ||
130 | * was a (very large) delta from full ftape_timestamps. | ||
131 | */ | ||
132 | return (t1 <= t0 && t0 <= LATCH) ? t1 + LATCH - t0 : t1 - t0; | ||
133 | #endif | ||
134 | } | ||
135 | |||
136 | static unsigned int usecs(unsigned int count) | ||
137 | { | ||
138 | #if defined(__alpha__) || defined(__x86_64__) | ||
139 | return (ps_per_cycle * count) / 1000000UL; | ||
140 | #elif defined(__i386__) | ||
141 | return (10000 * count) / ((CLOCK_TICK_RATE + 50) / 100); | ||
142 | #endif | ||
143 | } | ||
144 | |||
145 | unsigned int ftape_timediff(unsigned int t0, unsigned int t1) | ||
146 | { | ||
147 | /* | ||
148 | * Calculate difference in usec for ftape_timestamp results t0 & t1. | ||
149 | * Note that on the i386 platform with short time-stamps, the | ||
150 | * maximum allowed timespan is 1/HZ or we'll lose ticks! | ||
151 | */ | ||
152 | return usecs(diff(t0, t1)); | ||
153 | } | ||
154 | |||
155 | /* To get an indication of the I/O performance, | ||
156 | * measure the duration of the inb() function. | ||
157 | */ | ||
158 | static void time_inb(void) | ||
159 | { | ||
160 | int i; | ||
161 | int t0, t1; | ||
162 | unsigned long flags; | ||
163 | int status; | ||
164 | TRACE_FUN(ft_t_any); | ||
165 | |||
166 | spin_lock_irqsave(&calibr_lock, flags); | ||
167 | t0 = short_ftape_timestamp(); | ||
168 | for (i = 0; i < 1000; ++i) { | ||
169 | status = inb(fdc.msr); | ||
170 | } | ||
171 | t1 = short_ftape_timestamp(); | ||
172 | spin_unlock_irqrestore(&calibr_lock, flags); | ||
173 | TRACE(ft_t_info, "inb() duration: %d nsec", ftape_timediff(t0, t1)); | ||
174 | TRACE_EXIT; | ||
175 | } | ||
176 | |||
177 | static void init_clock(void) | ||
178 | { | ||
179 | TRACE_FUN(ft_t_any); | ||
180 | |||
181 | #if defined(__x86_64__) | ||
182 | ps_per_cycle = 1000000000UL / cpu_khz; | ||
183 | #elif defined(__alpha__) | ||
184 | extern struct hwrpb_struct *hwrpb; | ||
185 | ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq; | ||
186 | #endif | ||
187 | TRACE_EXIT; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Input: function taking int count as parameter. | ||
192 | * pointers to calculated calibration variables. | ||
193 | */ | ||
194 | void ftape_calibrate(char *name, | ||
195 | void (*fun) (unsigned int), | ||
196 | unsigned int *calibr_count, | ||
197 | unsigned int *calibr_time) | ||
198 | { | ||
199 | static int first_time = 1; | ||
200 | int i; | ||
201 | unsigned int tc = 0; | ||
202 | unsigned int count; | ||
203 | unsigned int time; | ||
204 | #if defined(__i386__) | ||
205 | unsigned int old_tc = 0; | ||
206 | unsigned int old_count = 1; | ||
207 | unsigned int old_time = 1; | ||
208 | #endif | ||
209 | TRACE_FUN(ft_t_flow); | ||
210 | |||
211 | if (first_time) { /* get idea of I/O performance */ | ||
212 | init_clock(); | ||
213 | time_inb(); | ||
214 | first_time = 0; | ||
215 | } | ||
216 | /* value of timeout must be set so that on very slow systems | ||
217 | * it will give a time less than one jiffy, and on | ||
218 | * very fast systems it'll give reasonable precision. | ||
219 | */ | ||
220 | |||
221 | count = 40; | ||
222 | for (i = 0; i < 15; ++i) { | ||
223 | unsigned int t0; | ||
224 | unsigned int t1; | ||
225 | unsigned int once; | ||
226 | unsigned int multiple; | ||
227 | unsigned long flags; | ||
228 | |||
229 | *calibr_count = | ||
230 | *calibr_time = count; /* set TC to 1 */ | ||
231 | spin_lock_irqsave(&calibr_lock, flags); | ||
232 | fun(0); /* dummy, get code into cache */ | ||
233 | t0 = short_ftape_timestamp(); | ||
234 | fun(0); /* overhead + one test */ | ||
235 | t1 = short_ftape_timestamp(); | ||
236 | once = diff(t0, t1); | ||
237 | t0 = short_ftape_timestamp(); | ||
238 | fun(count); /* overhead + count tests */ | ||
239 | t1 = short_ftape_timestamp(); | ||
240 | multiple = diff(t0, t1); | ||
241 | spin_unlock_irqrestore(&calibr_lock, flags); | ||
242 | time = ftape_timediff(0, multiple - once); | ||
243 | tc = (1000 * time) / (count - 1); | ||
244 | TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns", | ||
245 | usecs(once), count - 1, usecs(multiple), tc); | ||
246 | #if defined(__alpha__) || defined(__x86_64__) | ||
247 | /* | ||
248 | * Increase the calibration count exponentially until the | ||
249 | * calibration time exceeds 100 ms. | ||
250 | */ | ||
251 | if (time >= 100*1000) { | ||
252 | break; | ||
253 | } | ||
254 | #elif defined(__i386__) | ||
255 | /* | ||
256 | * increase the count until the resulting time nears 2/HZ, | ||
257 | * then the tc will drop sharply because we lose LATCH counts. | ||
258 | */ | ||
259 | if (tc <= old_tc / 2) { | ||
260 | time = old_time; | ||
261 | count = old_count; | ||
262 | break; | ||
263 | } | ||
264 | old_tc = tc; | ||
265 | old_count = count; | ||
266 | old_time = time; | ||
267 | #endif | ||
268 | count *= 2; | ||
269 | } | ||
270 | *calibr_count = count - 1; | ||
271 | *calibr_time = time; | ||
272 | TRACE(ft_t_info, "TC for `%s()' = %d nsec (at %d counts)", | ||
273 | name, (1000 * *calibr_time) / *calibr_count, *calibr_count); | ||
274 | TRACE_EXIT; | ||
275 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.h b/drivers/char/ftape/lowlevel/ftape-calibr.h deleted file mode 100644 index 0c7e75246c7d..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-calibr.h +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | #ifndef _FTAPE_CALIBR_H | ||
2 | #define _FTAPE_CALIBR_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-calibr.h,v $ | ||
23 | * $Revision: 1.1 $ | ||
24 | * $Date: 1997/09/19 09:05:26 $ | ||
25 | * | ||
26 | * This file contains a gp calibration routine for | ||
27 | * hardware dependent timeout functions. | ||
28 | */ | ||
29 | |||
30 | extern void ftape_calibrate(char *name, | ||
31 | void (*fun) (unsigned int), | ||
32 | unsigned int *calibr_count, | ||
33 | unsigned int *calibr_time); | ||
34 | extern unsigned int ftape_timestamp(void); | ||
35 | extern unsigned int ftape_timediff(unsigned int t0, unsigned int t1); | ||
36 | |||
37 | #endif /* _FTAPE_CALIBR_H */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.c b/drivers/char/ftape/lowlevel/ftape-ctl.c deleted file mode 100644 index 5d7c1ce92d59..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ctl.c +++ /dev/null | |||
@@ -1,896 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
3 | * 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: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ctl.c,v $ | ||
21 | * $Revision: 1.4 $ | ||
22 | * $Date: 1997/11/11 14:37:44 $ | ||
23 | * | ||
24 | * This file contains the non-read/write ftape functions for the | ||
25 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
26 | */ | ||
27 | |||
28 | #include <linux/errno.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/mman.h> | ||
31 | |||
32 | #include <linux/ftape.h> | ||
33 | #include <linux/qic117.h> | ||
34 | #include <asm/uaccess.h> | ||
35 | #include <asm/io.h> | ||
36 | |||
37 | /* ease porting between pre-2.4.x and later kernels */ | ||
38 | #define vma_get_pgoff(v) ((v)->vm_pgoff) | ||
39 | |||
40 | #include "../lowlevel/ftape-tracing.h" | ||
41 | #include "../lowlevel/ftape-io.h" | ||
42 | #include "../lowlevel/ftape-ctl.h" | ||
43 | #include "../lowlevel/ftape-write.h" | ||
44 | #include "../lowlevel/ftape-read.h" | ||
45 | #include "../lowlevel/ftape-rw.h" | ||
46 | #include "../lowlevel/ftape-bsm.h" | ||
47 | |||
48 | /* Global vars. | ||
49 | */ | ||
50 | ftape_info ftape_status = { | ||
51 | /* vendor information */ | ||
52 | { 0, }, /* drive type */ | ||
53 | /* data rates */ | ||
54 | 500, /* used data rate */ | ||
55 | 500, /* drive max rate */ | ||
56 | 500, /* fdc max rate */ | ||
57 | /* drive selection, either FTAPE_SEL_A/B/C/D */ | ||
58 | -1, /* drive selection */ | ||
59 | /* flags set after decode the drive and tape status */ | ||
60 | 0, /* formatted */ | ||
61 | 1, /* no tape */ | ||
62 | 1, /* write protected */ | ||
63 | 1, /* new tape */ | ||
64 | /* values of last queried drive/tape status and error */ | ||
65 | {{0,}}, /* last error code */ | ||
66 | {{0,}}, /* drive status, configuration, tape status */ | ||
67 | /* cartridge geometry */ | ||
68 | 20, /* tracks_per_tape */ | ||
69 | 102, /* segments_per_track */ | ||
70 | /* location of header segments, etc. */ | ||
71 | -1, /* used_header_segment */ | ||
72 | -1, /* header_segment_1 */ | ||
73 | -1, /* header_segment_2 */ | ||
74 | -1, /* first_data_segment */ | ||
75 | -1, /* last_data_segment */ | ||
76 | /* the format code as stored in the header segment */ | ||
77 | fmt_normal, /* format code */ | ||
78 | /* the default for the qic std: unknown */ | ||
79 | -1, | ||
80 | /* is tape running? */ | ||
81 | idle, /* runner_state */ | ||
82 | /* is tape reading/writing/verifying/formatting/deleting */ | ||
83 | idle, /* driver state */ | ||
84 | /* flags fatal hardware error */ | ||
85 | 1, /* failure */ | ||
86 | /* history record */ | ||
87 | { 0, } /* history record */ | ||
88 | }; | ||
89 | |||
90 | int ftape_segments_per_head = 1020; | ||
91 | int ftape_segments_per_cylinder = 4; | ||
92 | int ftape_init_drive_needed = 1; /* need to be global for ftape_reset_drive() | ||
93 | * in ftape-io.c | ||
94 | */ | ||
95 | |||
96 | /* Local vars. | ||
97 | */ | ||
98 | static const vendor_struct vendors[] = QIC117_VENDORS; | ||
99 | static const wakeup_method methods[] = WAKEUP_METHODS; | ||
100 | |||
101 | const ftape_info *ftape_get_status(void) | ||
102 | { | ||
103 | #if defined(STATUS_PARANOYA) | ||
104 | static ftape_info get_status; | ||
105 | |||
106 | get_status = ftape_status; | ||
107 | return &get_status; | ||
108 | #else | ||
109 | return &ftape_status; /* maybe return only a copy of it to assure | ||
110 | * read only access | ||
111 | */ | ||
112 | #endif | ||
113 | } | ||
114 | |||
115 | static int ftape_not_operational(int status) | ||
116 | { | ||
117 | /* return true if status indicates tape can not be used. | ||
118 | */ | ||
119 | return ((status ^ QIC_STATUS_CARTRIDGE_PRESENT) & | ||
120 | (QIC_STATUS_ERROR | | ||
121 | QIC_STATUS_CARTRIDGE_PRESENT | | ||
122 | QIC_STATUS_NEW_CARTRIDGE)); | ||
123 | } | ||
124 | |||
125 | int ftape_seek_to_eot(void) | ||
126 | { | ||
127 | int status; | ||
128 | TRACE_FUN(ft_t_any); | ||
129 | |||
130 | TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); | ||
131 | while ((status & QIC_STATUS_AT_EOT) == 0) { | ||
132 | if (ftape_not_operational(status)) { | ||
133 | TRACE_EXIT -EIO; | ||
134 | } | ||
135 | TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_FORWARD, | ||
136 | ftape_timeout.rewind,&status),); | ||
137 | } | ||
138 | TRACE_EXIT 0; | ||
139 | } | ||
140 | |||
141 | int ftape_seek_to_bot(void) | ||
142 | { | ||
143 | int status; | ||
144 | TRACE_FUN(ft_t_any); | ||
145 | |||
146 | TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); | ||
147 | while ((status & QIC_STATUS_AT_BOT) == 0) { | ||
148 | if (ftape_not_operational(status)) { | ||
149 | TRACE_EXIT -EIO; | ||
150 | } | ||
151 | TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_REVERSE, | ||
152 | ftape_timeout.rewind,&status),); | ||
153 | } | ||
154 | TRACE_EXIT 0; | ||
155 | } | ||
156 | |||
157 | static int ftape_new_cartridge(void) | ||
158 | { | ||
159 | ft_location.track = -1; /* force seek on first access */ | ||
160 | ftape_zap_read_buffers(); | ||
161 | ftape_zap_write_buffers(); | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | int ftape_abort_operation(void) | ||
166 | { | ||
167 | int result = 0; | ||
168 | int status; | ||
169 | TRACE_FUN(ft_t_flow); | ||
170 | |||
171 | if (ft_runner_status == running) { | ||
172 | TRACE(ft_t_noise, "aborting runner, waiting"); | ||
173 | |||
174 | ft_runner_status = do_abort; | ||
175 | /* set timeout so that the tape will run to logical EOT | ||
176 | * if we missed the last sector and there are no queue pulses. | ||
177 | */ | ||
178 | result = ftape_dumb_stop(); | ||
179 | } | ||
180 | if (ft_runner_status != idle) { | ||
181 | if (ft_runner_status == do_abort) { | ||
182 | TRACE(ft_t_noise, "forcing runner abort"); | ||
183 | } | ||
184 | TRACE(ft_t_noise, "stopping tape"); | ||
185 | result = ftape_stop_tape(&status); | ||
186 | ft_location.known = 0; | ||
187 | ft_runner_status = idle; | ||
188 | } | ||
189 | ftape_reset_buffer(); | ||
190 | ftape_zap_read_buffers(); | ||
191 | ftape_set_state(idle); | ||
192 | TRACE_EXIT result; | ||
193 | } | ||
194 | |||
195 | static int lookup_vendor_id(unsigned int vendor_id) | ||
196 | { | ||
197 | int i = 0; | ||
198 | |||
199 | while (vendors[i].vendor_id != vendor_id) { | ||
200 | if (++i >= NR_ITEMS(vendors)) { | ||
201 | return -1; | ||
202 | } | ||
203 | } | ||
204 | return i; | ||
205 | } | ||
206 | |||
207 | static void ftape_detach_drive(void) | ||
208 | { | ||
209 | TRACE_FUN(ft_t_any); | ||
210 | |||
211 | TRACE(ft_t_flow, "disabling tape drive and fdc"); | ||
212 | ftape_put_drive_to_sleep(ft_drive_type.wake_up); | ||
213 | fdc_catch_stray_interrupts(1); /* one always comes */ | ||
214 | fdc_disable(); | ||
215 | fdc_release_irq_and_dma(); | ||
216 | fdc_release_regions(); | ||
217 | TRACE_EXIT; | ||
218 | } | ||
219 | |||
220 | static void clear_history(void) | ||
221 | { | ||
222 | ft_history.used = 0; | ||
223 | ft_history.id_am_errors = | ||
224 | ft_history.id_crc_errors = | ||
225 | ft_history.data_am_errors = | ||
226 | ft_history.data_crc_errors = | ||
227 | ft_history.overrun_errors = | ||
228 | ft_history.no_data_errors = | ||
229 | ft_history.retries = | ||
230 | ft_history.crc_errors = | ||
231 | ft_history.crc_failures = | ||
232 | ft_history.ecc_failures = | ||
233 | ft_history.corrected = | ||
234 | ft_history.defects = | ||
235 | ft_history.rewinds = 0; | ||
236 | } | ||
237 | |||
238 | static int ftape_activate_drive(vendor_struct * drive_type) | ||
239 | { | ||
240 | int result = 0; | ||
241 | TRACE_FUN(ft_t_flow); | ||
242 | |||
243 | /* If we already know the drive type, wake it up. | ||
244 | * Else try to find out what kind of drive is attached. | ||
245 | */ | ||
246 | if (drive_type->wake_up != unknown_wake_up) { | ||
247 | TRACE(ft_t_flow, "enabling tape drive and fdc"); | ||
248 | result = ftape_wakeup_drive(drive_type->wake_up); | ||
249 | if (result < 0) { | ||
250 | TRACE(ft_t_err, "known wakeup method failed"); | ||
251 | } | ||
252 | } else { | ||
253 | wake_up_types method; | ||
254 | const ft_trace_t old_tracing = TRACE_LEVEL; | ||
255 | if (TRACE_LEVEL < ft_t_flow) { | ||
256 | SET_TRACE_LEVEL(ft_t_bug); | ||
257 | } | ||
258 | |||
259 | /* Try to awaken the drive using all known methods. | ||
260 | * Lower tracing for a while. | ||
261 | */ | ||
262 | for (method=no_wake_up; method < NR_ITEMS(methods); ++method) { | ||
263 | drive_type->wake_up = method; | ||
264 | #ifdef CONFIG_FT_TWO_DRIVES | ||
265 | /* Test setup for dual drive configuration. | ||
266 | * /dev/rft2 uses mountain wakeup | ||
267 | * /dev/rft3 uses colorado wakeup | ||
268 | * Other systems will use the normal scheme. | ||
269 | */ | ||
270 | if ((ft_drive_sel < 2) || | ||
271 | (ft_drive_sel == 2 && method == FT_WAKE_UP_1) || | ||
272 | (ft_drive_sel == 3 && method == FT_WAKE_UP_2)) { | ||
273 | result=ftape_wakeup_drive(drive_type->wake_up); | ||
274 | } else { | ||
275 | result = -EIO; | ||
276 | } | ||
277 | #else | ||
278 | result = ftape_wakeup_drive(drive_type->wake_up); | ||
279 | #endif | ||
280 | if (result >= 0) { | ||
281 | TRACE(ft_t_warn, "drive wakeup method: %s", | ||
282 | methods[drive_type->wake_up].name); | ||
283 | break; | ||
284 | } | ||
285 | } | ||
286 | SET_TRACE_LEVEL(old_tracing); | ||
287 | |||
288 | if (method >= NR_ITEMS(methods)) { | ||
289 | /* no response at all, cannot open this drive */ | ||
290 | drive_type->wake_up = unknown_wake_up; | ||
291 | TRACE(ft_t_err, "no tape drive found !"); | ||
292 | result = -ENODEV; | ||
293 | } | ||
294 | } | ||
295 | TRACE_EXIT result; | ||
296 | } | ||
297 | |||
298 | static int ftape_get_drive_status(void) | ||
299 | { | ||
300 | int result; | ||
301 | int status; | ||
302 | TRACE_FUN(ft_t_flow); | ||
303 | |||
304 | ft_no_tape = ft_write_protected = 0; | ||
305 | /* Tape drive is activated now. | ||
306 | * First clear error status if present. | ||
307 | */ | ||
308 | do { | ||
309 | result = ftape_ready_wait(ftape_timeout.reset, &status); | ||
310 | if (result < 0) { | ||
311 | if (result == -ETIME) { | ||
312 | TRACE(ft_t_err, "ftape_ready_wait timeout"); | ||
313 | } else if (result == -EINTR) { | ||
314 | TRACE(ft_t_err, "ftape_ready_wait aborted"); | ||
315 | } else { | ||
316 | TRACE(ft_t_err, "ftape_ready_wait failed"); | ||
317 | } | ||
318 | TRACE_EXIT -EIO; | ||
319 | } | ||
320 | /* Clear error condition (drive is ready !) | ||
321 | */ | ||
322 | if (status & QIC_STATUS_ERROR) { | ||
323 | unsigned int error; | ||
324 | qic117_cmd_t command; | ||
325 | |||
326 | TRACE(ft_t_err, "error status set"); | ||
327 | result = ftape_report_error(&error, &command, 1); | ||
328 | if (result < 0) { | ||
329 | TRACE(ft_t_err, | ||
330 | "report_error_code failed: %d", result); | ||
331 | /* hope it's working next time */ | ||
332 | ftape_reset_drive(); | ||
333 | TRACE_EXIT -EIO; | ||
334 | } else if (error != 0) { | ||
335 | TRACE(ft_t_noise, "error code : %d", error); | ||
336 | TRACE(ft_t_noise, "error command: %d", command); | ||
337 | } | ||
338 | } | ||
339 | if (status & QIC_STATUS_NEW_CARTRIDGE) { | ||
340 | unsigned int error; | ||
341 | qic117_cmd_t command; | ||
342 | const ft_trace_t old_tracing = TRACE_LEVEL; | ||
343 | SET_TRACE_LEVEL(ft_t_bug); | ||
344 | |||
345 | /* Undocumented feature: Must clear (not present!) | ||
346 | * error here or we'll fail later. | ||
347 | */ | ||
348 | ftape_report_error(&error, &command, 1); | ||
349 | |||
350 | SET_TRACE_LEVEL(old_tracing); | ||
351 | TRACE(ft_t_info, "status: new cartridge"); | ||
352 | ft_new_tape = 1; | ||
353 | } else { | ||
354 | ft_new_tape = 0; | ||
355 | } | ||
356 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
357 | } while (status & QIC_STATUS_ERROR); | ||
358 | |||
359 | ft_no_tape = !(status & QIC_STATUS_CARTRIDGE_PRESENT); | ||
360 | ft_write_protected = (status & QIC_STATUS_WRITE_PROTECT) != 0; | ||
361 | if (ft_no_tape) { | ||
362 | TRACE(ft_t_warn, "no cartridge present"); | ||
363 | } else { | ||
364 | if (ft_write_protected) { | ||
365 | TRACE(ft_t_noise, "Write protected cartridge"); | ||
366 | } | ||
367 | } | ||
368 | TRACE_EXIT 0; | ||
369 | } | ||
370 | |||
371 | static void ftape_log_vendor_id(void) | ||
372 | { | ||
373 | int vendor_index; | ||
374 | TRACE_FUN(ft_t_flow); | ||
375 | |||
376 | ftape_report_vendor_id(&ft_drive_type.vendor_id); | ||
377 | vendor_index = lookup_vendor_id(ft_drive_type.vendor_id); | ||
378 | if (ft_drive_type.vendor_id == UNKNOWN_VENDOR && | ||
379 | ft_drive_type.wake_up == wake_up_colorado) { | ||
380 | vendor_index = 0; | ||
381 | /* hack to get rid of all this mail */ | ||
382 | ft_drive_type.vendor_id = 0; | ||
383 | } | ||
384 | if (vendor_index < 0) { | ||
385 | /* Unknown vendor id, first time opening device. The | ||
386 | * drive_type remains set to type found at wakeup | ||
387 | * time, this will probably keep the driver operating | ||
388 | * for this new vendor. | ||
389 | */ | ||
390 | TRACE(ft_t_warn, "\n" | ||
391 | KERN_INFO "============ unknown vendor id ===========\n" | ||
392 | KERN_INFO "A new, yet unsupported tape drive is found\n" | ||
393 | KERN_INFO "Please report the following values:\n" | ||
394 | KERN_INFO " Vendor id : 0x%04x\n" | ||
395 | KERN_INFO " Wakeup method : %s\n" | ||
396 | KERN_INFO "And a description of your tape drive\n" | ||
397 | KERN_INFO "to "THE_FTAPE_MAINTAINER"\n" | ||
398 | KERN_INFO "==========================================", | ||
399 | ft_drive_type.vendor_id, | ||
400 | methods[ft_drive_type.wake_up].name); | ||
401 | ft_drive_type.speed = 0; /* unknown */ | ||
402 | } else { | ||
403 | ft_drive_type.name = vendors[vendor_index].name; | ||
404 | ft_drive_type.speed = vendors[vendor_index].speed; | ||
405 | TRACE(ft_t_info, "tape drive type: %s", ft_drive_type.name); | ||
406 | /* scan all methods for this vendor_id in table */ | ||
407 | while(ft_drive_type.wake_up != vendors[vendor_index].wake_up) { | ||
408 | if (vendor_index < NR_ITEMS(vendors) - 1 && | ||
409 | vendors[vendor_index + 1].vendor_id | ||
410 | == | ||
411 | ft_drive_type.vendor_id) { | ||
412 | ++vendor_index; | ||
413 | } else { | ||
414 | break; | ||
415 | } | ||
416 | } | ||
417 | if (ft_drive_type.wake_up != vendors[vendor_index].wake_up) { | ||
418 | TRACE(ft_t_warn, "\n" | ||
419 | KERN_INFO "==========================================\n" | ||
420 | KERN_INFO "wakeup type mismatch:\n" | ||
421 | KERN_INFO "found: %s, expected: %s\n" | ||
422 | KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n" | ||
423 | KERN_INFO "==========================================", | ||
424 | methods[ft_drive_type.wake_up].name, | ||
425 | methods[vendors[vendor_index].wake_up].name); | ||
426 | } | ||
427 | } | ||
428 | TRACE_EXIT; | ||
429 | } | ||
430 | |||
431 | void ftape_calc_timeouts(unsigned int qic_std, | ||
432 | unsigned int data_rate, | ||
433 | unsigned int tape_len) | ||
434 | { | ||
435 | int speed; /* deci-ips ! */ | ||
436 | int ff_speed; | ||
437 | int length; | ||
438 | TRACE_FUN(ft_t_any); | ||
439 | |||
440 | /* tape transport speed | ||
441 | * data rate: QIC-40 QIC-80 QIC-3010 QIC-3020 | ||
442 | * | ||
443 | * 250 Kbps 25 ips n/a n/a n/a | ||
444 | * 500 Kbps 50 ips 34 ips 22.6 ips n/a | ||
445 | * 1 Mbps n/a 68 ips 45.2 ips 22.6 ips | ||
446 | * 2 Mbps n/a n/a n/a 45.2 ips | ||
447 | * | ||
448 | * fast tape transport speed is at least 68 ips. | ||
449 | */ | ||
450 | switch (qic_std) { | ||
451 | case QIC_TAPE_QIC40: | ||
452 | speed = (data_rate == 250) ? 250 : 500; | ||
453 | break; | ||
454 | case QIC_TAPE_QIC80: | ||
455 | speed = (data_rate == 500) ? 340 : 680; | ||
456 | break; | ||
457 | case QIC_TAPE_QIC3010: | ||
458 | speed = (data_rate == 500) ? 226 : 452; | ||
459 | break; | ||
460 | case QIC_TAPE_QIC3020: | ||
461 | speed = (data_rate == 1000) ? 226 : 452; | ||
462 | break; | ||
463 | default: | ||
464 | TRACE(ft_t_bug, "Unknown qic_std (bug) ?"); | ||
465 | speed = 500; | ||
466 | break; | ||
467 | } | ||
468 | if (ft_drive_type.speed == 0) { | ||
469 | unsigned long t0; | ||
470 | static int dt = 0; /* keep gcc from complaining */ | ||
471 | static int first_time = 1; | ||
472 | |||
473 | /* Measure the time it takes to wind to EOT and back to BOT. | ||
474 | * If the tape length is known, calculate the rewind speed. | ||
475 | * Else keep the time value for calculation of the rewind | ||
476 | * speed later on, when the length _is_ known. | ||
477 | * Ask for a report only when length and speed are both known. | ||
478 | */ | ||
479 | if (first_time) { | ||
480 | ftape_seek_to_bot(); | ||
481 | t0 = jiffies; | ||
482 | ftape_seek_to_eot(); | ||
483 | ftape_seek_to_bot(); | ||
484 | dt = (int) (((jiffies - t0) * FT_USPT) / 1000); | ||
485 | if (dt < 1) { | ||
486 | dt = 1; /* prevent div by zero on failures */ | ||
487 | } | ||
488 | first_time = 0; | ||
489 | TRACE(ft_t_info, | ||
490 | "trying to determine seek timeout, got %d msec", | ||
491 | dt); | ||
492 | } | ||
493 | if (tape_len != 0) { | ||
494 | ft_drive_type.speed = | ||
495 | (2 * 12 * tape_len * 1000) / dt; | ||
496 | TRACE(ft_t_warn, "\n" | ||
497 | KERN_INFO "==========================================\n" | ||
498 | KERN_INFO "drive type: %s\n" | ||
499 | KERN_INFO "delta time = %d ms, length = %d ft\n" | ||
500 | KERN_INFO "has a maximum tape speed of %d ips\n" | ||
501 | KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n" | ||
502 | KERN_INFO "==========================================", | ||
503 | ft_drive_type.name, dt, tape_len, | ||
504 | ft_drive_type.speed); | ||
505 | } | ||
506 | } | ||
507 | /* Handle unknown length tapes as very long ones. We'll | ||
508 | * determine the actual length from a header segment later. | ||
509 | * This is normal for all modern (Wide,TR1/2/3) formats. | ||
510 | */ | ||
511 | if (tape_len <= 0) { | ||
512 | TRACE(ft_t_noise, | ||
513 | "Unknown tape length, using maximal timeouts"); | ||
514 | length = QIC_TOP_TAPE_LEN; /* use worst case values */ | ||
515 | } else { | ||
516 | length = tape_len; /* use actual values */ | ||
517 | } | ||
518 | if (ft_drive_type.speed == 0) { | ||
519 | ff_speed = speed; | ||
520 | } else { | ||
521 | ff_speed = ft_drive_type.speed; | ||
522 | } | ||
523 | /* time to go from bot to eot at normal speed (data rate): | ||
524 | * time = (1+delta) * length (ft) * 12 (inch/ft) / speed (ips) | ||
525 | * delta = 10 % for seek speed, 20 % for rewind speed. | ||
526 | */ | ||
527 | ftape_timeout.seek = (length * 132 * FT_SECOND) / speed; | ||
528 | ftape_timeout.rewind = (length * 144 * FT_SECOND) / (10 * ff_speed); | ||
529 | ftape_timeout.reset = 20 * FT_SECOND + ftape_timeout.rewind; | ||
530 | TRACE(ft_t_noise, "timeouts for speed = %d, length = %d\n" | ||
531 | KERN_INFO "seek timeout : %d sec\n" | ||
532 | KERN_INFO "rewind timeout: %d sec\n" | ||
533 | KERN_INFO "reset timeout : %d sec", | ||
534 | speed, length, | ||
535 | (ftape_timeout.seek + 500) / 1000, | ||
536 | (ftape_timeout.rewind + 500) / 1000, | ||
537 | (ftape_timeout.reset + 500) / 1000); | ||
538 | TRACE_EXIT; | ||
539 | } | ||
540 | |||
541 | /* This function calibrates the datarate (i.e. determines the maximal | ||
542 | * usable data rate) and sets the global variable ft_qic_std to qic_std | ||
543 | * | ||
544 | */ | ||
545 | int ftape_calibrate_data_rate(unsigned int qic_std) | ||
546 | { | ||
547 | int rate = ft_fdc_rate_limit; | ||
548 | int result; | ||
549 | TRACE_FUN(ft_t_flow); | ||
550 | |||
551 | ft_qic_std = qic_std; | ||
552 | |||
553 | if (ft_qic_std == -1) { | ||
554 | TRACE_ABORT(-EIO, ft_t_err, | ||
555 | "Unable to determine data rate if QIC standard is unknown"); | ||
556 | } | ||
557 | |||
558 | /* Select highest rate supported by both fdc and drive. | ||
559 | * Start with highest rate supported by the fdc. | ||
560 | */ | ||
561 | while (fdc_set_data_rate(rate) < 0 && rate > 250) { | ||
562 | rate /= 2; | ||
563 | } | ||
564 | TRACE(ft_t_info, | ||
565 | "Highest FDC supported data rate: %d Kbps", rate); | ||
566 | ft_fdc_max_rate = rate; | ||
567 | do { | ||
568 | result = ftape_set_data_rate(rate, ft_qic_std); | ||
569 | } while (result == -EINVAL && (rate /= 2) > 250); | ||
570 | if (result < 0) { | ||
571 | TRACE_ABORT(-EIO, ft_t_err, "set datarate failed"); | ||
572 | } | ||
573 | ft_data_rate = rate; | ||
574 | TRACE_EXIT 0; | ||
575 | } | ||
576 | |||
577 | static int ftape_init_drive(void) | ||
578 | { | ||
579 | int status; | ||
580 | qic_model model; | ||
581 | unsigned int qic_std; | ||
582 | unsigned int data_rate; | ||
583 | TRACE_FUN(ft_t_flow); | ||
584 | |||
585 | ftape_init_drive_needed = 0; /* don't retry if this fails ? */ | ||
586 | TRACE_CATCH(ftape_report_raw_drive_status(&status),); | ||
587 | if (status & QIC_STATUS_CARTRIDGE_PRESENT) { | ||
588 | if (!(status & QIC_STATUS_AT_BOT)) { | ||
589 | /* Antique drives will get here after a soft reset, | ||
590 | * modern ones only if the driver is loaded when the | ||
591 | * tape wasn't rewound properly. | ||
592 | */ | ||
593 | /* Tape should be at bot if new cartridge ! */ | ||
594 | ftape_seek_to_bot(); | ||
595 | } | ||
596 | if (!(status & QIC_STATUS_REFERENCED)) { | ||
597 | TRACE(ft_t_flow, "starting seek_load_point"); | ||
598 | TRACE_CATCH(ftape_command_wait(QIC_SEEK_LOAD_POINT, | ||
599 | ftape_timeout.reset, | ||
600 | &status),); | ||
601 | } | ||
602 | } | ||
603 | ft_formatted = (status & QIC_STATUS_REFERENCED) != 0; | ||
604 | if (!ft_formatted) { | ||
605 | TRACE(ft_t_warn, "Warning: tape is not formatted !"); | ||
606 | } | ||
607 | |||
608 | /* report configuration aborts when ftape_tape_len == -1 | ||
609 | * unknown qic_std is okay if not formatted. | ||
610 | */ | ||
611 | TRACE_CATCH(ftape_report_configuration(&model, | ||
612 | &data_rate, | ||
613 | &qic_std, | ||
614 | &ftape_tape_len),); | ||
615 | |||
616 | /* Maybe add the following to the /proc entry | ||
617 | */ | ||
618 | TRACE(ft_t_info, "%s drive @ %d Kbps", | ||
619 | (model == prehistoric) ? "prehistoric" : | ||
620 | ((model == pre_qic117c) ? "pre QIC-117C" : | ||
621 | ((model == post_qic117b) ? "post QIC-117B" : | ||
622 | "post QIC-117D")), data_rate); | ||
623 | |||
624 | if (ft_formatted) { | ||
625 | /* initialize ft_used_data_rate to maximum value | ||
626 | * and set ft_qic_std | ||
627 | */ | ||
628 | TRACE_CATCH(ftape_calibrate_data_rate(qic_std),); | ||
629 | if (ftape_tape_len == 0) { | ||
630 | TRACE(ft_t_info, "unknown length QIC-%s tape", | ||
631 | (ft_qic_std == QIC_TAPE_QIC40) ? "40" : | ||
632 | ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : | ||
633 | ((ft_qic_std == QIC_TAPE_QIC3010) | ||
634 | ? "3010" : "3020"))); | ||
635 | } else { | ||
636 | TRACE(ft_t_info, "%d ft. QIC-%s tape", ftape_tape_len, | ||
637 | (ft_qic_std == QIC_TAPE_QIC40) ? "40" : | ||
638 | ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : | ||
639 | ((ft_qic_std == QIC_TAPE_QIC3010) | ||
640 | ? "3010" : "3020"))); | ||
641 | } | ||
642 | ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); | ||
643 | /* soft write-protect QIC-40/QIC-80 cartridges used with a | ||
644 | * Colorado T3000 drive. Buggy hardware! | ||
645 | */ | ||
646 | if ((ft_drive_type.vendor_id == 0x011c6) && | ||
647 | ((ft_qic_std == QIC_TAPE_QIC40 || | ||
648 | ft_qic_std == QIC_TAPE_QIC80) && | ||
649 | !ft_write_protected)) { | ||
650 | TRACE(ft_t_warn, "\n" | ||
651 | KERN_INFO "The famous Colorado T3000 bug:\n" | ||
652 | KERN_INFO "%s drives can't write QIC40 and QIC80\n" | ||
653 | KERN_INFO "cartridges but don't set the write-protect flag!", | ||
654 | ft_drive_type.name); | ||
655 | ft_write_protected = 1; | ||
656 | } | ||
657 | } else { | ||
658 | /* Doesn't make too much sense to set the data rate | ||
659 | * because we don't know what to use for the write | ||
660 | * precompensation. | ||
661 | * Need to do this again when formatting the cartridge. | ||
662 | */ | ||
663 | ft_data_rate = data_rate; | ||
664 | ftape_calc_timeouts(QIC_TAPE_QIC40, | ||
665 | data_rate, | ||
666 | ftape_tape_len); | ||
667 | } | ||
668 | ftape_new_cartridge(); | ||
669 | TRACE_EXIT 0; | ||
670 | } | ||
671 | |||
672 | static void ftape_munmap(void) | ||
673 | { | ||
674 | int i; | ||
675 | TRACE_FUN(ft_t_flow); | ||
676 | |||
677 | for (i = 0; i < ft_nr_buffers; i++) { | ||
678 | ft_buffer[i]->mmapped = 0; | ||
679 | } | ||
680 | TRACE_EXIT; | ||
681 | } | ||
682 | |||
683 | /* Map the dma buffers into the virtual address range given by vma. | ||
684 | * We only check the caller doesn't map non-existent buffers. We | ||
685 | * don't check for multiple mappings. | ||
686 | */ | ||
687 | int ftape_mmap(struct vm_area_struct *vma) | ||
688 | { | ||
689 | int num_buffers; | ||
690 | int i; | ||
691 | TRACE_FUN(ft_t_flow); | ||
692 | |||
693 | if (ft_failure) { | ||
694 | TRACE_EXIT -ENODEV; | ||
695 | } | ||
696 | if (!(vma->vm_flags & (VM_READ|VM_WRITE))) { | ||
697 | TRACE_ABORT(-EINVAL, ft_t_err, "Undefined mmap() access"); | ||
698 | } | ||
699 | if (vma_get_pgoff(vma) != 0) { | ||
700 | TRACE_ABORT(-EINVAL, ft_t_err, "page offset must be 0"); | ||
701 | } | ||
702 | if ((vma->vm_end - vma->vm_start) % FT_BUFF_SIZE != 0) { | ||
703 | TRACE_ABORT(-EINVAL, ft_t_err, | ||
704 | "size = %ld, should be a multiple of %d", | ||
705 | vma->vm_end - vma->vm_start, | ||
706 | FT_BUFF_SIZE); | ||
707 | } | ||
708 | num_buffers = (vma->vm_end - vma->vm_start) / FT_BUFF_SIZE; | ||
709 | if (num_buffers > ft_nr_buffers) { | ||
710 | TRACE_ABORT(-EINVAL, | ||
711 | ft_t_err, "size = %ld, should be less than %d", | ||
712 | vma->vm_end - vma->vm_start, | ||
713 | ft_nr_buffers * FT_BUFF_SIZE); | ||
714 | } | ||
715 | if (ft_driver_state != idle) { | ||
716 | /* this also clears the buffer states | ||
717 | */ | ||
718 | ftape_abort_operation(); | ||
719 | } else { | ||
720 | ftape_reset_buffer(); | ||
721 | } | ||
722 | for (i = 0; i < num_buffers; i++) { | ||
723 | unsigned long pfn; | ||
724 | |||
725 | pfn = virt_to_phys(ft_buffer[i]->address) >> PAGE_SHIFT; | ||
726 | TRACE_CATCH(remap_pfn_range(vma, vma->vm_start + | ||
727 | i * FT_BUFF_SIZE, | ||
728 | pfn, | ||
729 | FT_BUFF_SIZE, | ||
730 | vma->vm_page_prot), | ||
731 | _res = -EAGAIN); | ||
732 | TRACE(ft_t_noise, "remapped dma buffer @ %p to location @ %p", | ||
733 | ft_buffer[i]->address, | ||
734 | (void *)(vma->vm_start + i * FT_BUFF_SIZE)); | ||
735 | } | ||
736 | for (i = 0; i < num_buffers; i++) { | ||
737 | memset(ft_buffer[i]->address, 0xAA, FT_BUFF_SIZE); | ||
738 | ft_buffer[i]->mmapped++; | ||
739 | } | ||
740 | TRACE_EXIT 0; | ||
741 | } | ||
742 | |||
743 | static void ftape_init_driver(void); /* forward declaration */ | ||
744 | |||
745 | /* OPEN routine called by kernel-interface code | ||
746 | */ | ||
747 | int ftape_enable(int drive_selection) | ||
748 | { | ||
749 | TRACE_FUN(ft_t_any); | ||
750 | |||
751 | if (ft_drive_sel == -1 || ft_drive_sel != drive_selection) { | ||
752 | /* Other selection than last time | ||
753 | */ | ||
754 | ftape_init_driver(); | ||
755 | } | ||
756 | ft_drive_sel = FTAPE_SEL(drive_selection); | ||
757 | ft_failure = 0; | ||
758 | TRACE_CATCH(fdc_init(),); /* init & detect fdc */ | ||
759 | TRACE_CATCH(ftape_activate_drive(&ft_drive_type), | ||
760 | fdc_disable(); | ||
761 | fdc_release_irq_and_dma(); | ||
762 | fdc_release_regions()); | ||
763 | TRACE_CATCH(ftape_get_drive_status(), ftape_detach_drive()); | ||
764 | if (ft_drive_type.vendor_id == UNKNOWN_VENDOR) { | ||
765 | ftape_log_vendor_id(); | ||
766 | } | ||
767 | if (ft_new_tape) { | ||
768 | ftape_init_drive_needed = 1; | ||
769 | } | ||
770 | if (!ft_no_tape && ftape_init_drive_needed) { | ||
771 | TRACE_CATCH(ftape_init_drive(), ftape_detach_drive()); | ||
772 | } | ||
773 | ftape_munmap(); /* clear the mmap flag */ | ||
774 | clear_history(); | ||
775 | TRACE_EXIT 0; | ||
776 | } | ||
777 | |||
778 | /* release routine called by the high level interface modules | ||
779 | * zftape or sftape. | ||
780 | */ | ||
781 | void ftape_disable(void) | ||
782 | { | ||
783 | int i; | ||
784 | TRACE_FUN(ft_t_any); | ||
785 | |||
786 | for (i = 0; i < ft_nr_buffers; i++) { | ||
787 | if (ft_buffer[i]->mmapped) { | ||
788 | TRACE(ft_t_noise, "first byte of buffer %d: 0x%02x", | ||
789 | i, *ft_buffer[i]->address); | ||
790 | } | ||
791 | } | ||
792 | if (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK) && | ||
793 | !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK)) && | ||
794 | ftape_tape_running) { | ||
795 | TRACE(ft_t_warn, | ||
796 | "Interrupted by fatal signal and tape still running"); | ||
797 | ftape_dumb_stop(); | ||
798 | ftape_abort_operation(); /* it's annoying */ | ||
799 | } else { | ||
800 | ftape_set_state(idle); | ||
801 | } | ||
802 | ftape_detach_drive(); | ||
803 | if (ft_history.used) { | ||
804 | TRACE(ft_t_info, "== Non-fatal errors this run: =="); | ||
805 | TRACE(ft_t_info, "fdc isr statistics:\n" | ||
806 | KERN_INFO " id_am_errors : %3d\n" | ||
807 | KERN_INFO " id_crc_errors : %3d\n" | ||
808 | KERN_INFO " data_am_errors : %3d\n" | ||
809 | KERN_INFO " data_crc_errors : %3d\n" | ||
810 | KERN_INFO " overrun_errors : %3d\n" | ||
811 | KERN_INFO " no_data_errors : %3d\n" | ||
812 | KERN_INFO " retries : %3d", | ||
813 | ft_history.id_am_errors, ft_history.id_crc_errors, | ||
814 | ft_history.data_am_errors, ft_history.data_crc_errors, | ||
815 | ft_history.overrun_errors, ft_history.no_data_errors, | ||
816 | ft_history.retries); | ||
817 | if (ft_history.used & 1) { | ||
818 | TRACE(ft_t_info, "ecc statistics:\n" | ||
819 | KERN_INFO " crc_errors : %3d\n" | ||
820 | KERN_INFO " crc_failures : %3d\n" | ||
821 | KERN_INFO " ecc_failures : %3d\n" | ||
822 | KERN_INFO " sectors corrected: %3d", | ||
823 | ft_history.crc_errors, ft_history.crc_failures, | ||
824 | ft_history.ecc_failures, ft_history.corrected); | ||
825 | } | ||
826 | if (ft_history.defects > 0) { | ||
827 | TRACE(ft_t_warn, "Warning: %d media defects!", | ||
828 | ft_history.defects); | ||
829 | } | ||
830 | if (ft_history.rewinds > 0) { | ||
831 | TRACE(ft_t_info, "tape motion statistics:\n" | ||
832 | KERN_INFO "repositions : %3d", | ||
833 | ft_history.rewinds); | ||
834 | } | ||
835 | } | ||
836 | ft_failure = 1; | ||
837 | TRACE_EXIT; | ||
838 | } | ||
839 | |||
840 | static void ftape_init_driver(void) | ||
841 | { | ||
842 | TRACE_FUN(ft_t_flow); | ||
843 | |||
844 | ft_drive_type.vendor_id = UNKNOWN_VENDOR; | ||
845 | ft_drive_type.speed = 0; | ||
846 | ft_drive_type.wake_up = unknown_wake_up; | ||
847 | ft_drive_type.name = "Unknown"; | ||
848 | |||
849 | ftape_timeout.seek = 650 * FT_SECOND; | ||
850 | ftape_timeout.reset = 670 * FT_SECOND; | ||
851 | ftape_timeout.rewind = 650 * FT_SECOND; | ||
852 | ftape_timeout.head_seek = 15 * FT_SECOND; | ||
853 | ftape_timeout.stop = 5 * FT_SECOND; | ||
854 | ftape_timeout.pause = 16 * FT_SECOND; | ||
855 | |||
856 | ft_qic_std = -1; | ||
857 | ftape_tape_len = 0; /* unknown */ | ||
858 | ftape_current_command = 0; | ||
859 | ftape_current_cylinder = -1; | ||
860 | |||
861 | ft_segments_per_track = 102; | ||
862 | ftape_segments_per_head = 1020; | ||
863 | ftape_segments_per_cylinder = 4; | ||
864 | ft_tracks_per_tape = 20; | ||
865 | |||
866 | ft_failure = 1; | ||
867 | |||
868 | ft_formatted = 0; | ||
869 | ft_no_tape = 1; | ||
870 | ft_write_protected = 1; | ||
871 | ft_new_tape = 1; | ||
872 | |||
873 | ft_driver_state = idle; | ||
874 | |||
875 | ft_data_rate = | ||
876 | ft_fdc_max_rate = 500; | ||
877 | ft_drive_max_rate = 0; /* triggers set_rate_test() */ | ||
878 | |||
879 | ftape_init_drive_needed = 1; | ||
880 | |||
881 | ft_header_segment_1 = -1; | ||
882 | ft_header_segment_2 = -1; | ||
883 | ft_used_header_segment = -1; | ||
884 | ft_first_data_segment = -1; | ||
885 | ft_last_data_segment = -1; | ||
886 | |||
887 | ft_location.track = -1; | ||
888 | ft_location.known = 0; | ||
889 | |||
890 | ftape_tape_running = 0; | ||
891 | ftape_might_be_off_track = 1; | ||
892 | |||
893 | ftape_new_cartridge(); /* init some tape related variables */ | ||
894 | ftape_init_bsm(); | ||
895 | TRACE_EXIT; | ||
896 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.h b/drivers/char/ftape/lowlevel/ftape-ctl.h deleted file mode 100644 index 5f5e30bc3615..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ctl.h +++ /dev/null | |||
@@ -1,162 +0,0 @@ | |||
1 | #ifndef _FTAPE_CTL_H | ||
2 | #define _FTAPE_CTL_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ctl.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:09 $ | ||
26 | * | ||
27 | * This file contains the non-standard IOCTL related definitions | ||
28 | * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for | ||
29 | * Linux. | ||
30 | */ | ||
31 | |||
32 | #include <linux/ioctl.h> | ||
33 | #include <linux/mtio.h> | ||
34 | #include <linux/ftape-vendors.h> | ||
35 | |||
36 | #include "../lowlevel/ftape-rw.h" | ||
37 | #include <linux/ftape-header-segment.h> | ||
38 | |||
39 | typedef struct { | ||
40 | int used; /* any reading or writing done */ | ||
41 | /* isr statistics */ | ||
42 | unsigned int id_am_errors; /* id address mark not found */ | ||
43 | unsigned int id_crc_errors; /* crc error in id address mark */ | ||
44 | unsigned int data_am_errors; /* data address mark not found */ | ||
45 | unsigned int data_crc_errors; /* crc error in data field */ | ||
46 | unsigned int overrun_errors; /* fdc access timing problem */ | ||
47 | unsigned int no_data_errors; /* sector not found */ | ||
48 | unsigned int retries; /* number of tape retries */ | ||
49 | /* ecc statistics */ | ||
50 | unsigned int crc_errors; /* crc error in data */ | ||
51 | unsigned int crc_failures; /* bad data without crc error */ | ||
52 | unsigned int ecc_failures; /* failed to correct */ | ||
53 | unsigned int corrected; /* total sectors corrected */ | ||
54 | /* general statistics */ | ||
55 | unsigned int rewinds; /* number of tape rewinds */ | ||
56 | unsigned int defects; /* bad sectors due to media defects */ | ||
57 | } history_record; | ||
58 | |||
59 | /* this structure contains * ALL * information that we want | ||
60 | * our child modules to know about, but don't want them to | ||
61 | * modify. | ||
62 | */ | ||
63 | typedef struct { | ||
64 | /* vendor information */ | ||
65 | vendor_struct fti_drive_type; | ||
66 | /* data rates */ | ||
67 | unsigned int fti_used_data_rate; | ||
68 | unsigned int fti_drive_max_rate; | ||
69 | unsigned int fti_fdc_max_rate; | ||
70 | /* drive selection, either FTAPE_SEL_A/B/C/D */ | ||
71 | int fti_drive_sel; | ||
72 | /* flags set after decode the drive and tape status */ | ||
73 | unsigned int fti_formatted :1; | ||
74 | unsigned int fti_no_tape :1; | ||
75 | unsigned int fti_write_protected:1; | ||
76 | unsigned int fti_new_tape :1; | ||
77 | /* values of last queried drive/tape status and error */ | ||
78 | ft_drive_error fti_last_error; | ||
79 | ft_drive_status fti_last_status; | ||
80 | /* cartridge geometry */ | ||
81 | unsigned int fti_tracks_per_tape; | ||
82 | unsigned int fti_segments_per_track; | ||
83 | /* location of header segments, etc. */ | ||
84 | int fti_used_header_segment; | ||
85 | int fti_header_segment_1; | ||
86 | int fti_header_segment_2; | ||
87 | int fti_first_data_segment; | ||
88 | int fti_last_data_segment; | ||
89 | /* the format code as stored in the header segment */ | ||
90 | ft_format_type fti_format_code; | ||
91 | /* the following is the sole reason for the ftape_set_status() call */ | ||
92 | unsigned int fti_qic_std; | ||
93 | /* is tape running? */ | ||
94 | volatile enum runner_status_enum fti_runner_status; | ||
95 | /* is tape reading/writing/verifying/formatting/deleting */ | ||
96 | buffer_state_enum fti_state; | ||
97 | /* flags fatal hardware error */ | ||
98 | unsigned int fti_failure:1; | ||
99 | /* history record */ | ||
100 | history_record fti_history; | ||
101 | } ftape_info; | ||
102 | |||
103 | /* vendor information */ | ||
104 | #define ft_drive_type ftape_status.fti_drive_type | ||
105 | /* data rates */ | ||
106 | #define ft_data_rate ftape_status.fti_used_data_rate | ||
107 | #define ft_drive_max_rate ftape_status.fti_drive_max_rate | ||
108 | #define ft_fdc_max_rate ftape_status.fti_fdc_max_rate | ||
109 | /* drive selection, either FTAPE_SEL_A/B/C/D */ | ||
110 | #define ft_drive_sel ftape_status.fti_drive_sel | ||
111 | /* flags set after decode the drive and tape status */ | ||
112 | #define ft_formatted ftape_status.fti_formatted | ||
113 | #define ft_no_tape ftape_status.fti_no_tape | ||
114 | #define ft_write_protected ftape_status.fti_write_protected | ||
115 | #define ft_new_tape ftape_status.fti_new_tape | ||
116 | /* values of last queried drive/tape status and error */ | ||
117 | #define ft_last_error ftape_status.fti_last_error | ||
118 | #define ft_last_status ftape_status.fti_last_status | ||
119 | /* cartridge geometry */ | ||
120 | #define ft_tracks_per_tape ftape_status.fti_tracks_per_tape | ||
121 | #define ft_segments_per_track ftape_status.fti_segments_per_track | ||
122 | /* the format code as stored in the header segment */ | ||
123 | #define ft_format_code ftape_status.fti_format_code | ||
124 | /* the qic status as returned by report drive configuration */ | ||
125 | #define ft_qic_std ftape_status.fti_qic_std | ||
126 | #define ft_used_header_segment ftape_status.fti_used_header_segment | ||
127 | #define ft_header_segment_1 ftape_status.fti_header_segment_1 | ||
128 | #define ft_header_segment_2 ftape_status.fti_header_segment_2 | ||
129 | #define ft_first_data_segment ftape_status.fti_first_data_segment | ||
130 | #define ft_last_data_segment ftape_status.fti_last_data_segment | ||
131 | /* is tape running? */ | ||
132 | #define ft_runner_status ftape_status.fti_runner_status | ||
133 | /* is tape reading/writing/verifying/formatting/deleting */ | ||
134 | #define ft_driver_state ftape_status.fti_state | ||
135 | /* flags fatal hardware error */ | ||
136 | #define ft_failure ftape_status.fti_failure | ||
137 | /* history record */ | ||
138 | #define ft_history ftape_status.fti_history | ||
139 | |||
140 | /* | ||
141 | * ftape-ctl.c defined global vars. | ||
142 | */ | ||
143 | extern ftape_info ftape_status; | ||
144 | extern int ftape_segments_per_head; | ||
145 | extern int ftape_segments_per_cylinder; | ||
146 | extern int ftape_init_drive_needed; | ||
147 | |||
148 | /* | ||
149 | * ftape-ctl.c defined global functions. | ||
150 | */ | ||
151 | extern int ftape_mmap(struct vm_area_struct *vma); | ||
152 | extern int ftape_enable(int drive_selection); | ||
153 | extern void ftape_disable(void); | ||
154 | extern int ftape_seek_to_bot(void); | ||
155 | extern int ftape_seek_to_eot(void); | ||
156 | extern int ftape_abort_operation(void); | ||
157 | extern void ftape_calc_timeouts(unsigned int qic_std, | ||
158 | unsigned int data_rate, | ||
159 | unsigned int tape_len); | ||
160 | extern int ftape_calibrate_data_rate(unsigned int qic_std); | ||
161 | extern const ftape_info *ftape_get_status(void); | ||
162 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-ecc.c b/drivers/char/ftape/lowlevel/ftape-ecc.c deleted file mode 100644 index e5632f674bc8..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ecc.c +++ /dev/null | |||
@@ -1,853 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 1993 Ning and David Mosberger. | ||
4 | |||
5 | This is based on code originally written by Bas Laarhoven (bas@vimec.nl) | ||
6 | and David L. Brown, Jr., and incorporates improvements suggested by | ||
7 | Kai Harrekilde-Petersen. | ||
8 | |||
9 | This program is free software; you can redistribute it and/or | ||
10 | modify it under the terms of the GNU General Public License as | ||
11 | published by the Free Software Foundation; either version 2, or (at | ||
12 | your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, but | ||
15 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; see the file COPYING. If not, write to | ||
21 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | ||
22 | USA. | ||
23 | |||
24 | * | ||
25 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ecc.c,v $ | ||
26 | * $Revision: 1.3 $ | ||
27 | * $Date: 1997/10/05 19:18:10 $ | ||
28 | * | ||
29 | * This file contains the Reed-Solomon error correction code | ||
30 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
31 | */ | ||
32 | |||
33 | #include <linux/ftape.h> | ||
34 | |||
35 | #include "../lowlevel/ftape-tracing.h" | ||
36 | #include "../lowlevel/ftape-ecc.h" | ||
37 | |||
38 | /* Machines that are big-endian should define macro BIG_ENDIAN. | ||
39 | * Unfortunately, there doesn't appear to be a standard include file | ||
40 | * that works for all OSs. | ||
41 | */ | ||
42 | |||
43 | #if defined(__sparc__) || defined(__hppa) | ||
44 | #define BIG_ENDIAN | ||
45 | #endif /* __sparc__ || __hppa */ | ||
46 | |||
47 | #if defined(__mips__) | ||
48 | #error Find a smart way to determine the Endianness of the MIPS CPU | ||
49 | #endif | ||
50 | |||
51 | /* Notice: to minimize the potential for confusion, we use r to | ||
52 | * denote the independent variable of the polynomials in the | ||
53 | * Galois Field GF(2^8). We reserve x for polynomials that | ||
54 | * that have coefficients in GF(2^8). | ||
55 | * | ||
56 | * The Galois Field in which coefficient arithmetic is performed are | ||
57 | * the polynomials over Z_2 (i.e., 0 and 1) modulo the irreducible | ||
58 | * polynomial f(r), where f(r)=r^8 + r^7 + r^2 + r + 1. A polynomial | ||
59 | * is represented as a byte with the MSB as the coefficient of r^7 and | ||
60 | * the LSB as the coefficient of r^0. For example, the binary | ||
61 | * representation of f(x) is 0x187 (of course, this doesn't fit into 8 | ||
62 | * bits). In this field, the polynomial r is a primitive element. | ||
63 | * That is, r^i with i in 0,...,255 enumerates all elements in the | ||
64 | * field. | ||
65 | * | ||
66 | * The generator polynomial for the QIC-80 ECC is | ||
67 | * | ||
68 | * g(x) = x^3 + r^105*x^2 + r^105*x + 1 | ||
69 | * | ||
70 | * which can be factored into: | ||
71 | * | ||
72 | * g(x) = (x-r^-1)(x-r^0)(x-r^1) | ||
73 | * | ||
74 | * the byte representation of the coefficients are: | ||
75 | * | ||
76 | * r^105 = 0xc0 | ||
77 | * r^-1 = 0xc3 | ||
78 | * r^0 = 0x01 | ||
79 | * r^1 = 0x02 | ||
80 | * | ||
81 | * Notice that r^-1 = r^254 as exponent arithmetic is performed | ||
82 | * modulo 2^8-1 = 255. | ||
83 | * | ||
84 | * For more information on Galois Fields and Reed-Solomon codes, refer | ||
85 | * to any good book. I found _An Introduction to Error Correcting | ||
86 | * Codes with Applications_ by S. A. Vanstone and P. C. van Oorschot | ||
87 | * to be a good introduction into the former. _CODING THEORY: The | ||
88 | * Essentials_ I found very useful for its concise description of | ||
89 | * Reed-Solomon encoding/decoding. | ||
90 | * | ||
91 | */ | ||
92 | |||
93 | typedef __u8 Matrix[3][3]; | ||
94 | |||
95 | /* | ||
96 | * gfpow[] is defined such that gfpow[i] returns r^i if | ||
97 | * i is in the range [0..255]. | ||
98 | */ | ||
99 | static const __u8 gfpow[] = | ||
100 | { | ||
101 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, | ||
102 | 0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4, | ||
103 | 0x6f, 0xde, 0x3b, 0x76, 0xec, 0x5f, 0xbe, 0xfb, | ||
104 | 0x71, 0xe2, 0x43, 0x86, 0x8b, 0x91, 0xa5, 0xcd, | ||
105 | 0x1d, 0x3a, 0x74, 0xe8, 0x57, 0xae, 0xdb, 0x31, | ||
106 | 0x62, 0xc4, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0x67, | ||
107 | 0xce, 0x1b, 0x36, 0x6c, 0xd8, 0x37, 0x6e, 0xdc, | ||
108 | 0x3f, 0x7e, 0xfc, 0x7f, 0xfe, 0x7b, 0xf6, 0x6b, | ||
109 | 0xd6, 0x2b, 0x56, 0xac, 0xdf, 0x39, 0x72, 0xe4, | ||
110 | 0x4f, 0x9e, 0xbb, 0xf1, 0x65, 0xca, 0x13, 0x26, | ||
111 | 0x4c, 0x98, 0xb7, 0xe9, 0x55, 0xaa, 0xd3, 0x21, | ||
112 | 0x42, 0x84, 0x8f, 0x99, 0xb5, 0xed, 0x5d, 0xba, | ||
113 | 0xf3, 0x61, 0xc2, 0x03, 0x06, 0x0c, 0x18, 0x30, | ||
114 | 0x60, 0xc0, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, | ||
115 | 0x47, 0x8e, 0x9b, 0xb1, 0xe5, 0x4d, 0x9a, 0xb3, | ||
116 | 0xe1, 0x45, 0x8a, 0x93, 0xa1, 0xc5, 0x0d, 0x1a, | ||
117 | 0x34, 0x68, 0xd0, 0x27, 0x4e, 0x9c, 0xbf, 0xf9, | ||
118 | 0x75, 0xea, 0x53, 0xa6, 0xcb, 0x11, 0x22, 0x44, | ||
119 | 0x88, 0x97, 0xa9, 0xd5, 0x2d, 0x5a, 0xb4, 0xef, | ||
120 | 0x59, 0xb2, 0xe3, 0x41, 0x82, 0x83, 0x81, 0x85, | ||
121 | 0x8d, 0x9d, 0xbd, 0xfd, 0x7d, 0xfa, 0x73, 0xe6, | ||
122 | 0x4b, 0x96, 0xab, 0xd1, 0x25, 0x4a, 0x94, 0xaf, | ||
123 | 0xd9, 0x35, 0x6a, 0xd4, 0x2f, 0x5e, 0xbc, 0xff, | ||
124 | 0x79, 0xf2, 0x63, 0xc6, 0x0b, 0x16, 0x2c, 0x58, | ||
125 | 0xb0, 0xe7, 0x49, 0x92, 0xa3, 0xc1, 0x05, 0x0a, | ||
126 | 0x14, 0x28, 0x50, 0xa0, 0xc7, 0x09, 0x12, 0x24, | ||
127 | 0x48, 0x90, 0xa7, 0xc9, 0x15, 0x2a, 0x54, 0xa8, | ||
128 | 0xd7, 0x29, 0x52, 0xa4, 0xcf, 0x19, 0x32, 0x64, | ||
129 | 0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2, | ||
130 | 0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda, | ||
131 | 0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77, | ||
132 | 0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3, 0x01 | ||
133 | }; | ||
134 | |||
135 | /* | ||
136 | * This is a log table. That is, gflog[r^i] returns i (modulo f(r)). | ||
137 | * gflog[0] is undefined and the first element is therefore not valid. | ||
138 | */ | ||
139 | static const __u8 gflog[256] = | ||
140 | { | ||
141 | 0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a, | ||
142 | 0x03, 0xcd, 0xc7, 0xbc, 0x65, 0x7e, 0x6b, 0x2a, | ||
143 | 0x04, 0x8d, 0xce, 0x4e, 0xc8, 0xd4, 0xbd, 0xe1, | ||
144 | 0x66, 0xdd, 0x7f, 0x31, 0x6c, 0x20, 0x2b, 0xf3, | ||
145 | 0x05, 0x57, 0x8e, 0xe8, 0xcf, 0xac, 0x4f, 0x83, | ||
146 | 0xc9, 0xd9, 0xd5, 0x41, 0xbe, 0x94, 0xe2, 0xb4, | ||
147 | 0x67, 0x27, 0xde, 0xf0, 0x80, 0xb1, 0x32, 0x35, | ||
148 | 0x6d, 0x45, 0x21, 0x12, 0x2c, 0x0d, 0xf4, 0x38, | ||
149 | 0x06, 0x9b, 0x58, 0x1a, 0x8f, 0x79, 0xe9, 0x70, | ||
150 | 0xd0, 0xc2, 0xad, 0xa8, 0x50, 0x75, 0x84, 0x48, | ||
151 | 0xca, 0xfc, 0xda, 0x8a, 0xd6, 0x54, 0x42, 0x24, | ||
152 | 0xbf, 0x98, 0x95, 0xf9, 0xe3, 0x5e, 0xb5, 0x15, | ||
153 | 0x68, 0x61, 0x28, 0xba, 0xdf, 0x4c, 0xf1, 0x2f, | ||
154 | 0x81, 0xe6, 0xb2, 0x3f, 0x33, 0xee, 0x36, 0x10, | ||
155 | 0x6e, 0x18, 0x46, 0xa6, 0x22, 0x88, 0x13, 0xf7, | ||
156 | 0x2d, 0xb8, 0x0e, 0x3d, 0xf5, 0xa4, 0x39, 0x3b, | ||
157 | 0x07, 0x9e, 0x9c, 0x9d, 0x59, 0x9f, 0x1b, 0x08, | ||
158 | 0x90, 0x09, 0x7a, 0x1c, 0xea, 0xa0, 0x71, 0x5a, | ||
159 | 0xd1, 0x1d, 0xc3, 0x7b, 0xae, 0x0a, 0xa9, 0x91, | ||
160 | 0x51, 0x5b, 0x76, 0x72, 0x85, 0xa1, 0x49, 0xeb, | ||
161 | 0xcb, 0x7c, 0xfd, 0xc4, 0xdb, 0x1e, 0x8b, 0xd2, | ||
162 | 0xd7, 0x92, 0x55, 0xaa, 0x43, 0x0b, 0x25, 0xaf, | ||
163 | 0xc0, 0x73, 0x99, 0x77, 0x96, 0x5c, 0xfa, 0x52, | ||
164 | 0xe4, 0xec, 0x5f, 0x4a, 0xb6, 0xa2, 0x16, 0x86, | ||
165 | 0x69, 0xc5, 0x62, 0xfe, 0x29, 0x7d, 0xbb, 0xcc, | ||
166 | 0xe0, 0xd3, 0x4d, 0x8c, 0xf2, 0x1f, 0x30, 0xdc, | ||
167 | 0x82, 0xab, 0xe7, 0x56, 0xb3, 0x93, 0x40, 0xd8, | ||
168 | 0x34, 0xb0, 0xef, 0x26, 0x37, 0x0c, 0x11, 0x44, | ||
169 | 0x6f, 0x78, 0x19, 0x9a, 0x47, 0x74, 0xa7, 0xc1, | ||
170 | 0x23, 0x53, 0x89, 0xfb, 0x14, 0x5d, 0xf8, 0x97, | ||
171 | 0x2e, 0x4b, 0xb9, 0x60, 0x0f, 0xed, 0x3e, 0xe5, | ||
172 | 0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7 | ||
173 | }; | ||
174 | |||
175 | /* This is a multiplication table for the factor 0xc0 (i.e., r^105 (mod f(r)). | ||
176 | * gfmul_c0[f] returns r^105 * f(r) (modulo f(r)). | ||
177 | */ | ||
178 | static const __u8 gfmul_c0[256] = | ||
179 | { | ||
180 | 0x00, 0xc0, 0x07, 0xc7, 0x0e, 0xce, 0x09, 0xc9, | ||
181 | 0x1c, 0xdc, 0x1b, 0xdb, 0x12, 0xd2, 0x15, 0xd5, | ||
182 | 0x38, 0xf8, 0x3f, 0xff, 0x36, 0xf6, 0x31, 0xf1, | ||
183 | 0x24, 0xe4, 0x23, 0xe3, 0x2a, 0xea, 0x2d, 0xed, | ||
184 | 0x70, 0xb0, 0x77, 0xb7, 0x7e, 0xbe, 0x79, 0xb9, | ||
185 | 0x6c, 0xac, 0x6b, 0xab, 0x62, 0xa2, 0x65, 0xa5, | ||
186 | 0x48, 0x88, 0x4f, 0x8f, 0x46, 0x86, 0x41, 0x81, | ||
187 | 0x54, 0x94, 0x53, 0x93, 0x5a, 0x9a, 0x5d, 0x9d, | ||
188 | 0xe0, 0x20, 0xe7, 0x27, 0xee, 0x2e, 0xe9, 0x29, | ||
189 | 0xfc, 0x3c, 0xfb, 0x3b, 0xf2, 0x32, 0xf5, 0x35, | ||
190 | 0xd8, 0x18, 0xdf, 0x1f, 0xd6, 0x16, 0xd1, 0x11, | ||
191 | 0xc4, 0x04, 0xc3, 0x03, 0xca, 0x0a, 0xcd, 0x0d, | ||
192 | 0x90, 0x50, 0x97, 0x57, 0x9e, 0x5e, 0x99, 0x59, | ||
193 | 0x8c, 0x4c, 0x8b, 0x4b, 0x82, 0x42, 0x85, 0x45, | ||
194 | 0xa8, 0x68, 0xaf, 0x6f, 0xa6, 0x66, 0xa1, 0x61, | ||
195 | 0xb4, 0x74, 0xb3, 0x73, 0xba, 0x7a, 0xbd, 0x7d, | ||
196 | 0x47, 0x87, 0x40, 0x80, 0x49, 0x89, 0x4e, 0x8e, | ||
197 | 0x5b, 0x9b, 0x5c, 0x9c, 0x55, 0x95, 0x52, 0x92, | ||
198 | 0x7f, 0xbf, 0x78, 0xb8, 0x71, 0xb1, 0x76, 0xb6, | ||
199 | 0x63, 0xa3, 0x64, 0xa4, 0x6d, 0xad, 0x6a, 0xaa, | ||
200 | 0x37, 0xf7, 0x30, 0xf0, 0x39, 0xf9, 0x3e, 0xfe, | ||
201 | 0x2b, 0xeb, 0x2c, 0xec, 0x25, 0xe5, 0x22, 0xe2, | ||
202 | 0x0f, 0xcf, 0x08, 0xc8, 0x01, 0xc1, 0x06, 0xc6, | ||
203 | 0x13, 0xd3, 0x14, 0xd4, 0x1d, 0xdd, 0x1a, 0xda, | ||
204 | 0xa7, 0x67, 0xa0, 0x60, 0xa9, 0x69, 0xae, 0x6e, | ||
205 | 0xbb, 0x7b, 0xbc, 0x7c, 0xb5, 0x75, 0xb2, 0x72, | ||
206 | 0x9f, 0x5f, 0x98, 0x58, 0x91, 0x51, 0x96, 0x56, | ||
207 | 0x83, 0x43, 0x84, 0x44, 0x8d, 0x4d, 0x8a, 0x4a, | ||
208 | 0xd7, 0x17, 0xd0, 0x10, 0xd9, 0x19, 0xde, 0x1e, | ||
209 | 0xcb, 0x0b, 0xcc, 0x0c, 0xc5, 0x05, 0xc2, 0x02, | ||
210 | 0xef, 0x2f, 0xe8, 0x28, 0xe1, 0x21, 0xe6, 0x26, | ||
211 | 0xf3, 0x33, 0xf4, 0x34, 0xfd, 0x3d, 0xfa, 0x3a | ||
212 | }; | ||
213 | |||
214 | |||
215 | /* Returns V modulo 255 provided V is in the range -255,-254,...,509. | ||
216 | */ | ||
217 | static inline __u8 mod255(int v) | ||
218 | { | ||
219 | if (v > 0) { | ||
220 | if (v < 255) { | ||
221 | return v; | ||
222 | } else { | ||
223 | return v - 255; | ||
224 | } | ||
225 | } else { | ||
226 | return v + 255; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | |||
231 | /* Add two numbers in the field. Addition in this field is equivalent | ||
232 | * to a bit-wise exclusive OR operation---subtraction is therefore | ||
233 | * identical to addition. | ||
234 | */ | ||
235 | static inline __u8 gfadd(__u8 a, __u8 b) | ||
236 | { | ||
237 | return a ^ b; | ||
238 | } | ||
239 | |||
240 | |||
241 | /* Add two vectors of numbers in the field. Each byte in A and B gets | ||
242 | * added individually. | ||
243 | */ | ||
244 | static inline unsigned long gfadd_long(unsigned long a, unsigned long b) | ||
245 | { | ||
246 | return a ^ b; | ||
247 | } | ||
248 | |||
249 | |||
250 | /* Multiply two numbers in the field: | ||
251 | */ | ||
252 | static inline __u8 gfmul(__u8 a, __u8 b) | ||
253 | { | ||
254 | if (a && b) { | ||
255 | return gfpow[mod255(gflog[a] + gflog[b])]; | ||
256 | } else { | ||
257 | return 0; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | |||
262 | /* Just like gfmul, except we have already looked up the log of the | ||
263 | * second number. | ||
264 | */ | ||
265 | static inline __u8 gfmul_exp(__u8 a, int b) | ||
266 | { | ||
267 | if (a) { | ||
268 | return gfpow[mod255(gflog[a] + b)]; | ||
269 | } else { | ||
270 | return 0; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | |||
275 | /* Just like gfmul_exp, except that A is a vector of numbers. That | ||
276 | * is, each byte in A gets multiplied by gfpow[mod255(B)]. | ||
277 | */ | ||
278 | static inline unsigned long gfmul_exp_long(unsigned long a, int b) | ||
279 | { | ||
280 | __u8 t; | ||
281 | |||
282 | if (sizeof(long) == 4) { | ||
283 | return ( | ||
284 | ((t = (__u32)a >> 24 & 0xff) ? | ||
285 | (((__u32) gfpow[mod255(gflog[t] + b)]) << 24) : 0) | | ||
286 | ((t = (__u32)a >> 16 & 0xff) ? | ||
287 | (((__u32) gfpow[mod255(gflog[t] + b)]) << 16) : 0) | | ||
288 | ((t = (__u32)a >> 8 & 0xff) ? | ||
289 | (((__u32) gfpow[mod255(gflog[t] + b)]) << 8) : 0) | | ||
290 | ((t = (__u32)a >> 0 & 0xff) ? | ||
291 | (((__u32) gfpow[mod255(gflog[t] + b)]) << 0) : 0)); | ||
292 | } else if (sizeof(long) == 8) { | ||
293 | return ( | ||
294 | ((t = (__u64)a >> 56 & 0xff) ? | ||
295 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 56) : 0) | | ||
296 | ((t = (__u64)a >> 48 & 0xff) ? | ||
297 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 48) : 0) | | ||
298 | ((t = (__u64)a >> 40 & 0xff) ? | ||
299 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 40) : 0) | | ||
300 | ((t = (__u64)a >> 32 & 0xff) ? | ||
301 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 32) : 0) | | ||
302 | ((t = (__u64)a >> 24 & 0xff) ? | ||
303 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 24) : 0) | | ||
304 | ((t = (__u64)a >> 16 & 0xff) ? | ||
305 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 16) : 0) | | ||
306 | ((t = (__u64)a >> 8 & 0xff) ? | ||
307 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 8) : 0) | | ||
308 | ((t = (__u64)a >> 0 & 0xff) ? | ||
309 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 0) : 0)); | ||
310 | } else { | ||
311 | TRACE_FUN(ft_t_any); | ||
312 | TRACE_ABORT(-1, ft_t_err, "Error: size of long is %d bytes", | ||
313 | (int)sizeof(long)); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | |||
318 | /* Divide two numbers in the field. Returns a/b (modulo f(x)). | ||
319 | */ | ||
320 | static inline __u8 gfdiv(__u8 a, __u8 b) | ||
321 | { | ||
322 | if (!b) { | ||
323 | TRACE_FUN(ft_t_any); | ||
324 | TRACE_ABORT(0xff, ft_t_bug, "Error: division by zero"); | ||
325 | } else if (a == 0) { | ||
326 | return 0; | ||
327 | } else { | ||
328 | return gfpow[mod255(gflog[a] - gflog[b])]; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | |||
333 | /* The following functions return the inverse of the matrix of the | ||
334 | * linear system that needs to be solved to determine the error | ||
335 | * magnitudes. The first deals with matrices of rank 3, while the | ||
336 | * second deals with matrices of rank 2. The error indices are passed | ||
337 | * in arguments L0,..,L2 (0=first sector, 31=last sector). The error | ||
338 | * indices must be sorted in ascending order, i.e., L0<L1<L2. | ||
339 | * | ||
340 | * The linear system that needs to be solved for the error magnitudes | ||
341 | * is A * b = s, where s is the known vector of syndromes, b is the | ||
342 | * vector of error magnitudes and A in the ORDER=3 case: | ||
343 | * | ||
344 | * A_3 = {{1/r^L[0], 1/r^L[1], 1/r^L[2]}, | ||
345 | * { 1, 1, 1}, | ||
346 | * { r^L[0], r^L[1], r^L[2]}} | ||
347 | */ | ||
348 | static inline int gfinv3(__u8 l0, | ||
349 | __u8 l1, | ||
350 | __u8 l2, | ||
351 | Matrix Ainv) | ||
352 | { | ||
353 | __u8 det; | ||
354 | __u8 t20, t10, t21, t12, t01, t02; | ||
355 | int log_det; | ||
356 | |||
357 | /* compute some intermediate results: */ | ||
358 | t20 = gfpow[l2 - l0]; /* t20 = r^l2/r^l0 */ | ||
359 | t10 = gfpow[l1 - l0]; /* t10 = r^l1/r^l0 */ | ||
360 | t21 = gfpow[l2 - l1]; /* t21 = r^l2/r^l1 */ | ||
361 | t12 = gfpow[l1 - l2 + 255]; /* t12 = r^l1/r^l2 */ | ||
362 | t01 = gfpow[l0 - l1 + 255]; /* t01 = r^l0/r^l1 */ | ||
363 | t02 = gfpow[l0 - l2 + 255]; /* t02 = r^l0/r^l2 */ | ||
364 | /* Calculate the determinant of matrix A_3^-1 (sometimes | ||
365 | * called the Vandermonde determinant): | ||
366 | */ | ||
367 | det = gfadd(t20, gfadd(t10, gfadd(t21, gfadd(t12, gfadd(t01, t02))))); | ||
368 | if (!det) { | ||
369 | TRACE_FUN(ft_t_any); | ||
370 | TRACE_ABORT(0, ft_t_err, | ||
371 | "Inversion failed (3 CRC errors, >0 CRC failures)"); | ||
372 | } | ||
373 | log_det = 255 - gflog[det]; | ||
374 | |||
375 | /* Now, calculate all of the coefficients: | ||
376 | */ | ||
377 | Ainv[0][0]= gfmul_exp(gfadd(gfpow[l1], gfpow[l2]), log_det); | ||
378 | Ainv[0][1]= gfmul_exp(gfadd(t21, t12), log_det); | ||
379 | Ainv[0][2]= gfmul_exp(gfadd(gfpow[255 - l1], gfpow[255 - l2]),log_det); | ||
380 | |||
381 | Ainv[1][0]= gfmul_exp(gfadd(gfpow[l0], gfpow[l2]), log_det); | ||
382 | Ainv[1][1]= gfmul_exp(gfadd(t20, t02), log_det); | ||
383 | Ainv[1][2]= gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l2]),log_det); | ||
384 | |||
385 | Ainv[2][0]= gfmul_exp(gfadd(gfpow[l0], gfpow[l1]), log_det); | ||
386 | Ainv[2][1]= gfmul_exp(gfadd(t10, t01), log_det); | ||
387 | Ainv[2][2]= gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l1]),log_det); | ||
388 | |||
389 | return 1; | ||
390 | } | ||
391 | |||
392 | |||
393 | static inline int gfinv2(__u8 l0, __u8 l1, Matrix Ainv) | ||
394 | { | ||
395 | __u8 det; | ||
396 | __u8 t1, t2; | ||
397 | int log_det; | ||
398 | |||
399 | t1 = gfpow[255 - l0]; | ||
400 | t2 = gfpow[255 - l1]; | ||
401 | det = gfadd(t1, t2); | ||
402 | if (!det) { | ||
403 | TRACE_FUN(ft_t_any); | ||
404 | TRACE_ABORT(0, ft_t_err, | ||
405 | "Inversion failed (2 CRC errors, >0 CRC failures)"); | ||
406 | } | ||
407 | log_det = 255 - gflog[det]; | ||
408 | |||
409 | /* Now, calculate all of the coefficients: | ||
410 | */ | ||
411 | Ainv[0][0] = Ainv[1][0] = gfpow[log_det]; | ||
412 | |||
413 | Ainv[0][1] = gfmul_exp(t2, log_det); | ||
414 | Ainv[1][1] = gfmul_exp(t1, log_det); | ||
415 | |||
416 | return 1; | ||
417 | } | ||
418 | |||
419 | |||
420 | /* Multiply matrix A by vector S and return result in vector B. M is | ||
421 | * assumed to be of order NxN, S and B of order Nx1. | ||
422 | */ | ||
423 | static inline void gfmat_mul(int n, Matrix A, | ||
424 | __u8 *s, __u8 *b) | ||
425 | { | ||
426 | int i, j; | ||
427 | __u8 dot_prod; | ||
428 | |||
429 | for (i = 0; i < n; ++i) { | ||
430 | dot_prod = 0; | ||
431 | for (j = 0; j < n; ++j) { | ||
432 | dot_prod = gfadd(dot_prod, gfmul(A[i][j], s[j])); | ||
433 | } | ||
434 | b[i] = dot_prod; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | |||
439 | |||
440 | /* The Reed Solomon ECC codes are computed over the N-th byte of each | ||
441 | * block, where N=SECTOR_SIZE. There are up to 29 blocks of data, and | ||
442 | * 3 blocks of ECC. The blocks are stored contiguously in memory. A | ||
443 | * segment, consequently, is assumed to have at least 4 blocks: one or | ||
444 | * more data blocks plus three ECC blocks. | ||
445 | * | ||
446 | * Notice: In QIC-80 speak, a CRC error is a sector with an incorrect | ||
447 | * CRC. A CRC failure is a sector with incorrect data, but | ||
448 | * a valid CRC. In the error control literature, the former | ||
449 | * is usually called "erasure", the latter "error." | ||
450 | */ | ||
451 | /* Compute the parity bytes for C columns of data, where C is the | ||
452 | * number of bytes that fit into a long integer. We use a linear | ||
453 | * feed-back register to do this. The parity bytes P[0], P[STRIDE], | ||
454 | * P[2*STRIDE] are computed such that: | ||
455 | * | ||
456 | * x^k * p(x) + m(x) = 0 (modulo g(x)) | ||
457 | * | ||
458 | * where k = NBLOCKS, | ||
459 | * p(x) = P[0] + P[STRIDE]*x + P[2*STRIDE]*x^2, and | ||
460 | * m(x) = sum_{i=0}^k m_i*x^i. | ||
461 | * m_i = DATA[i*SECTOR_SIZE] | ||
462 | */ | ||
463 | static inline void set_parity(unsigned long *data, | ||
464 | int nblocks, | ||
465 | unsigned long *p, | ||
466 | int stride) | ||
467 | { | ||
468 | unsigned long p0, p1, p2, t1, t2, *end; | ||
469 | |||
470 | end = data + nblocks * (FT_SECTOR_SIZE / sizeof(long)); | ||
471 | p0 = p1 = p2 = 0; | ||
472 | while (data < end) { | ||
473 | /* The new parity bytes p0_i, p1_i, p2_i are computed | ||
474 | * from the old values p0_{i-1}, p1_{i-1}, p2_{i-1} | ||
475 | * recursively as: | ||
476 | * | ||
477 | * p0_i = p1_{i-1} + r^105 * (m_{i-1} - p0_{i-1}) | ||
478 | * p1_i = p2_{i-1} + r^105 * (m_{i-1} - p0_{i-1}) | ||
479 | * p2_i = (m_{i-1} - p0_{i-1}) | ||
480 | * | ||
481 | * With the initial condition: p0_0 = p1_0 = p2_0 = 0. | ||
482 | */ | ||
483 | t1 = gfadd_long(*data, p0); | ||
484 | /* | ||
485 | * Multiply each byte in t1 by 0xc0: | ||
486 | */ | ||
487 | if (sizeof(long) == 4) { | ||
488 | t2= (((__u32) gfmul_c0[(__u32)t1 >> 24 & 0xff]) << 24 | | ||
489 | ((__u32) gfmul_c0[(__u32)t1 >> 16 & 0xff]) << 16 | | ||
490 | ((__u32) gfmul_c0[(__u32)t1 >> 8 & 0xff]) << 8 | | ||
491 | ((__u32) gfmul_c0[(__u32)t1 >> 0 & 0xff]) << 0); | ||
492 | } else if (sizeof(long) == 8) { | ||
493 | t2= (((__u64) gfmul_c0[(__u64)t1 >> 56 & 0xff]) << 56 | | ||
494 | ((__u64) gfmul_c0[(__u64)t1 >> 48 & 0xff]) << 48 | | ||
495 | ((__u64) gfmul_c0[(__u64)t1 >> 40 & 0xff]) << 40 | | ||
496 | ((__u64) gfmul_c0[(__u64)t1 >> 32 & 0xff]) << 32 | | ||
497 | ((__u64) gfmul_c0[(__u64)t1 >> 24 & 0xff]) << 24 | | ||
498 | ((__u64) gfmul_c0[(__u64)t1 >> 16 & 0xff]) << 16 | | ||
499 | ((__u64) gfmul_c0[(__u64)t1 >> 8 & 0xff]) << 8 | | ||
500 | ((__u64) gfmul_c0[(__u64)t1 >> 0 & 0xff]) << 0); | ||
501 | } else { | ||
502 | TRACE_FUN(ft_t_any); | ||
503 | TRACE(ft_t_err, "Error: long is of size %d", | ||
504 | (int) sizeof(long)); | ||
505 | TRACE_EXIT; | ||
506 | } | ||
507 | p0 = gfadd_long(t2, p1); | ||
508 | p1 = gfadd_long(t2, p2); | ||
509 | p2 = t1; | ||
510 | data += FT_SECTOR_SIZE / sizeof(long); | ||
511 | } | ||
512 | *p = p0; | ||
513 | p += stride; | ||
514 | *p = p1; | ||
515 | p += stride; | ||
516 | *p = p2; | ||
517 | return; | ||
518 | } | ||
519 | |||
520 | |||
521 | /* Compute the 3 syndrome values. DATA should point to the first byte | ||
522 | * of the column for which the syndromes are desired. The syndromes | ||
523 | * are computed over the first NBLOCKS of rows. The three bytes will | ||
524 | * be placed in S[0], S[1], and S[2]. | ||
525 | * | ||
526 | * S[i] is the value of the "message" polynomial m(x) evaluated at the | ||
527 | * i-th root of the generator polynomial g(x). | ||
528 | * | ||
529 | * As g(x)=(x-r^-1)(x-1)(x-r^1) we evaluate the message polynomial at | ||
530 | * x=r^-1 to get S[0], at x=r^0=1 to get S[1], and at x=r to get S[2]. | ||
531 | * This could be done directly and efficiently via the Horner scheme. | ||
532 | * However, it would require multiplication tables for the factors | ||
533 | * r^-1 (0xc3) and r (0x02). The following scheme does not require | ||
534 | * any multiplication tables beyond what's needed for set_parity() | ||
535 | * anyway and is slightly faster if there are no errors and slightly | ||
536 | * slower if there are errors. The latter is hopefully the infrequent | ||
537 | * case. | ||
538 | * | ||
539 | * To understand the alternative algorithm, notice that set_parity(m, | ||
540 | * k, p) computes parity bytes such that: | ||
541 | * | ||
542 | * x^k * p(x) = m(x) (modulo g(x)). | ||
543 | * | ||
544 | * That is, to evaluate m(r^m), where r^m is a root of g(x), we can | ||
545 | * simply evaluate (r^m)^k*p(r^m). Also, notice that p is 0 if and | ||
546 | * only if s is zero. That is, if all parity bytes are 0, we know | ||
547 | * there is no error in the data and consequently there is no need to | ||
548 | * compute s(x) at all! In all other cases, we compute s(x) from p(x) | ||
549 | * by evaluating (r^m)^k*p(r^m) for m=-1, m=0, and m=1. The p(x) | ||
550 | * polynomial is evaluated via the Horner scheme. | ||
551 | */ | ||
552 | static int compute_syndromes(unsigned long *data, int nblocks, unsigned long *s) | ||
553 | { | ||
554 | unsigned long p[3]; | ||
555 | |||
556 | set_parity(data, nblocks, p, 1); | ||
557 | if (p[0] | p[1] | p[2]) { | ||
558 | /* Some of the checked columns do not have a zero | ||
559 | * syndrome. For simplicity, we compute the syndromes | ||
560 | * for all columns that we have computed the | ||
561 | * remainders for. | ||
562 | */ | ||
563 | s[0] = gfmul_exp_long( | ||
564 | gfadd_long(p[0], | ||
565 | gfmul_exp_long( | ||
566 | gfadd_long(p[1], | ||
567 | gfmul_exp_long(p[2], -1)), | ||
568 | -1)), | ||
569 | -nblocks); | ||
570 | s[1] = gfadd_long(gfadd_long(p[2], p[1]), p[0]); | ||
571 | s[2] = gfmul_exp_long( | ||
572 | gfadd_long(p[0], | ||
573 | gfmul_exp_long( | ||
574 | gfadd_long(p[1], | ||
575 | gfmul_exp_long(p[2], 1)), | ||
576 | 1)), | ||
577 | nblocks); | ||
578 | return 0; | ||
579 | } else { | ||
580 | return 1; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | |||
585 | /* Correct the block in the column pointed to by DATA. There are NBAD | ||
586 | * CRC errors and their indices are in BAD_LOC[0], up to | ||
587 | * BAD_LOC[NBAD-1]. If NBAD>1, Ainv holds the inverse of the matrix | ||
588 | * of the linear system that needs to be solved to determine the error | ||
589 | * magnitudes. S[0], S[1], and S[2] are the syndrome values. If row | ||
590 | * j gets corrected, then bit j will be set in CORRECTION_MAP. | ||
591 | */ | ||
592 | static inline int correct_block(__u8 *data, int nblocks, | ||
593 | int nbad, int *bad_loc, Matrix Ainv, | ||
594 | __u8 *s, | ||
595 | SectorMap * correction_map) | ||
596 | { | ||
597 | int ncorrected = 0; | ||
598 | int i; | ||
599 | __u8 t1, t2; | ||
600 | __u8 c0, c1, c2; /* check bytes */ | ||
601 | __u8 error_mag[3], log_error_mag; | ||
602 | __u8 *dp, l, e; | ||
603 | TRACE_FUN(ft_t_any); | ||
604 | |||
605 | switch (nbad) { | ||
606 | case 0: | ||
607 | /* might have a CRC failure: */ | ||
608 | if (s[0] == 0) { | ||
609 | /* more than one error */ | ||
610 | TRACE_ABORT(-1, ft_t_err, | ||
611 | "ECC failed (0 CRC errors, >1 CRC failures)"); | ||
612 | } | ||
613 | t1 = gfdiv(s[1], s[0]); | ||
614 | if ((bad_loc[nbad++] = gflog[t1]) >= nblocks) { | ||
615 | TRACE(ft_t_err, | ||
616 | "ECC failed (0 CRC errors, >1 CRC failures)"); | ||
617 | TRACE_ABORT(-1, ft_t_err, | ||
618 | "attempt to correct data at %d", bad_loc[0]); | ||
619 | } | ||
620 | error_mag[0] = s[1]; | ||
621 | break; | ||
622 | case 1: | ||
623 | t1 = gfadd(gfmul_exp(s[1], bad_loc[0]), s[2]); | ||
624 | t2 = gfadd(gfmul_exp(s[0], bad_loc[0]), s[1]); | ||
625 | if (t1 == 0 && t2 == 0) { | ||
626 | /* one erasure, no error: */ | ||
627 | Ainv[0][0] = gfpow[bad_loc[0]]; | ||
628 | } else if (t1 == 0 || t2 == 0) { | ||
629 | /* one erasure and more than one error: */ | ||
630 | TRACE_ABORT(-1, ft_t_err, | ||
631 | "ECC failed (1 erasure, >1 error)"); | ||
632 | } else { | ||
633 | /* one erasure, one error: */ | ||
634 | if ((bad_loc[nbad++] = gflog[gfdiv(t1, t2)]) | ||
635 | >= nblocks) { | ||
636 | TRACE(ft_t_err, "ECC failed " | ||
637 | "(1 CRC errors, >1 CRC failures)"); | ||
638 | TRACE_ABORT(-1, ft_t_err, | ||
639 | "attempt to correct data at %d", | ||
640 | bad_loc[1]); | ||
641 | } | ||
642 | if (!gfinv2(bad_loc[0], bad_loc[1], Ainv)) { | ||
643 | /* inversion failed---must have more | ||
644 | * than one error | ||
645 | */ | ||
646 | TRACE_EXIT -1; | ||
647 | } | ||
648 | } | ||
649 | /* FALL THROUGH TO ERROR MAGNITUDE COMPUTATION: | ||
650 | */ | ||
651 | case 2: | ||
652 | case 3: | ||
653 | /* compute error magnitudes: */ | ||
654 | gfmat_mul(nbad, Ainv, s, error_mag); | ||
655 | break; | ||
656 | |||
657 | default: | ||
658 | TRACE_ABORT(-1, ft_t_err, | ||
659 | "Internal Error: number of CRC errors > 3"); | ||
660 | } | ||
661 | |||
662 | /* Perform correction by adding ERROR_MAG[i] to the byte at | ||
663 | * offset BAD_LOC[i]. Also add the value of the computed | ||
664 | * error polynomial to the syndrome values. If the correction | ||
665 | * was successful, the resulting check bytes should be zero | ||
666 | * (i.e., the corrected data is a valid code word). | ||
667 | */ | ||
668 | c0 = s[0]; | ||
669 | c1 = s[1]; | ||
670 | c2 = s[2]; | ||
671 | for (i = 0; i < nbad; ++i) { | ||
672 | e = error_mag[i]; | ||
673 | if (e) { | ||
674 | /* correct the byte at offset L by magnitude E: */ | ||
675 | l = bad_loc[i]; | ||
676 | dp = &data[l * FT_SECTOR_SIZE]; | ||
677 | *dp = gfadd(*dp, e); | ||
678 | *correction_map |= 1 << l; | ||
679 | ++ncorrected; | ||
680 | |||
681 | log_error_mag = gflog[e]; | ||
682 | c0 = gfadd(c0, gfpow[mod255(log_error_mag - l)]); | ||
683 | c1 = gfadd(c1, e); | ||
684 | c2 = gfadd(c2, gfpow[mod255(log_error_mag + l)]); | ||
685 | } | ||
686 | } | ||
687 | if (c0 || c1 || c2) { | ||
688 | TRACE_ABORT(-1, ft_t_err, | ||
689 | "ECC self-check failed, too many errors"); | ||
690 | } | ||
691 | TRACE_EXIT ncorrected; | ||
692 | } | ||
693 | |||
694 | |||
695 | #if defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) | ||
696 | |||
697 | /* Perform a sanity check on the computed parity bytes: | ||
698 | */ | ||
699 | static int sanity_check(unsigned long *data, int nblocks) | ||
700 | { | ||
701 | TRACE_FUN(ft_t_any); | ||
702 | unsigned long s[3]; | ||
703 | |||
704 | if (!compute_syndromes(data, nblocks, s)) { | ||
705 | TRACE_ABORT(0, ft_bug, | ||
706 | "Internal Error: syndrome self-check failed"); | ||
707 | } | ||
708 | TRACE_EXIT 1; | ||
709 | } | ||
710 | |||
711 | #endif /* defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) */ | ||
712 | |||
713 | /* Compute the parity for an entire segment of data. | ||
714 | */ | ||
715 | int ftape_ecc_set_segment_parity(struct memory_segment *mseg) | ||
716 | { | ||
717 | int i; | ||
718 | __u8 *parity_bytes; | ||
719 | |||
720 | parity_bytes = &mseg->data[(mseg->blocks - 3) * FT_SECTOR_SIZE]; | ||
721 | for (i = 0; i < FT_SECTOR_SIZE; i += sizeof(long)) { | ||
722 | set_parity((unsigned long *) &mseg->data[i], mseg->blocks - 3, | ||
723 | (unsigned long *) &parity_bytes[i], | ||
724 | FT_SECTOR_SIZE / sizeof(long)); | ||
725 | #ifdef ECC_PARANOID | ||
726 | if (!sanity_check((unsigned long *) &mseg->data[i], | ||
727 | mseg->blocks)) { | ||
728 | return -1; | ||
729 | } | ||
730 | #endif /* ECC_PARANOID */ | ||
731 | } | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | |||
736 | /* Checks and corrects (if possible) the segment MSEG. Returns one of | ||
737 | * ECC_OK, ECC_CORRECTED, and ECC_FAILED. | ||
738 | */ | ||
739 | int ftape_ecc_correct_data(struct memory_segment *mseg) | ||
740 | { | ||
741 | int col, i, result; | ||
742 | int ncorrected = 0; | ||
743 | int nerasures = 0; /* # of erasures (CRC errors) */ | ||
744 | int erasure_loc[3]; /* erasure locations */ | ||
745 | unsigned long ss[3]; | ||
746 | __u8 s[3]; | ||
747 | Matrix Ainv; | ||
748 | TRACE_FUN(ft_t_flow); | ||
749 | |||
750 | mseg->corrected = 0; | ||
751 | |||
752 | /* find first column that has non-zero syndromes: */ | ||
753 | for (col = 0; col < FT_SECTOR_SIZE; col += sizeof(long)) { | ||
754 | if (!compute_syndromes((unsigned long *) &mseg->data[col], | ||
755 | mseg->blocks, ss)) { | ||
756 | /* something is wrong---have to fix things */ | ||
757 | break; | ||
758 | } | ||
759 | } | ||
760 | if (col >= FT_SECTOR_SIZE) { | ||
761 | /* all syndromes are ok, therefore nothing to correct */ | ||
762 | TRACE_EXIT ECC_OK; | ||
763 | } | ||
764 | /* count the number of CRC errors if there were any: */ | ||
765 | if (mseg->read_bad) { | ||
766 | for (i = 0; i < mseg->blocks; i++) { | ||
767 | if (BAD_CHECK(mseg->read_bad, i)) { | ||
768 | if (nerasures >= 3) { | ||
769 | /* this is too much for ECC */ | ||
770 | TRACE_ABORT(ECC_FAILED, ft_t_err, | ||
771 | "ECC failed (>3 CRC errors)"); | ||
772 | } /* if */ | ||
773 | erasure_loc[nerasures++] = i; | ||
774 | } | ||
775 | } | ||
776 | } | ||
777 | /* | ||
778 | * If there are at least 2 CRC errors, determine inverse of matrix | ||
779 | * of linear system to be solved: | ||
780 | */ | ||
781 | switch (nerasures) { | ||
782 | case 2: | ||
783 | if (!gfinv2(erasure_loc[0], erasure_loc[1], Ainv)) { | ||
784 | TRACE_EXIT ECC_FAILED; | ||
785 | } | ||
786 | break; | ||
787 | case 3: | ||
788 | if (!gfinv3(erasure_loc[0], erasure_loc[1], | ||
789 | erasure_loc[2], Ainv)) { | ||
790 | TRACE_EXIT ECC_FAILED; | ||
791 | } | ||
792 | break; | ||
793 | default: | ||
794 | /* this is not an error condition... */ | ||
795 | break; | ||
796 | } | ||
797 | |||
798 | do { | ||
799 | for (i = 0; i < sizeof(long); ++i) { | ||
800 | s[0] = ss[0]; | ||
801 | s[1] = ss[1]; | ||
802 | s[2] = ss[2]; | ||
803 | if (s[0] | s[1] | s[2]) { | ||
804 | #ifdef BIG_ENDIAN | ||
805 | result = correct_block( | ||
806 | &mseg->data[col + sizeof(long) - 1 - i], | ||
807 | mseg->blocks, | ||
808 | nerasures, | ||
809 | erasure_loc, | ||
810 | Ainv, | ||
811 | s, | ||
812 | &mseg->corrected); | ||
813 | #else | ||
814 | result = correct_block(&mseg->data[col + i], | ||
815 | mseg->blocks, | ||
816 | nerasures, | ||
817 | erasure_loc, | ||
818 | Ainv, | ||
819 | s, | ||
820 | &mseg->corrected); | ||
821 | #endif | ||
822 | if (result < 0) { | ||
823 | TRACE_EXIT ECC_FAILED; | ||
824 | } | ||
825 | ncorrected += result; | ||
826 | } | ||
827 | ss[0] >>= 8; | ||
828 | ss[1] >>= 8; | ||
829 | ss[2] >>= 8; | ||
830 | } | ||
831 | |||
832 | #ifdef ECC_SANITY_CHECK | ||
833 | if (!sanity_check((unsigned long *) &mseg->data[col], | ||
834 | mseg->blocks)) { | ||
835 | TRACE_EXIT ECC_FAILED; | ||
836 | } | ||
837 | #endif /* ECC_SANITY_CHECK */ | ||
838 | |||
839 | /* find next column with non-zero syndromes: */ | ||
840 | while ((col += sizeof(long)) < FT_SECTOR_SIZE) { | ||
841 | if (!compute_syndromes((unsigned long *) | ||
842 | &mseg->data[col], mseg->blocks, ss)) { | ||
843 | /* something is wrong---have to fix things */ | ||
844 | break; | ||
845 | } | ||
846 | } | ||
847 | } while (col < FT_SECTOR_SIZE); | ||
848 | if (ncorrected && nerasures == 0) { | ||
849 | TRACE(ft_t_warn, "block contained error not caught by CRC"); | ||
850 | } | ||
851 | TRACE((ncorrected > 0) ? ft_t_noise : ft_t_any, "number of corrections: %d", ncorrected); | ||
852 | TRACE_EXIT ncorrected ? ECC_CORRECTED : ECC_OK; | ||
853 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-ecc.h b/drivers/char/ftape/lowlevel/ftape-ecc.h deleted file mode 100644 index 4829146fe9a0..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ecc.h +++ /dev/null | |||
@@ -1,84 +0,0 @@ | |||
1 | #ifndef _FTAPE_ECC_H_ | ||
2 | #define _FTAPE_ECC_H_ | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993 Ning and David Mosberger. | ||
6 | * Original: | ||
7 | * Copyright (C) 1993 Bas Laarhoven. | ||
8 | * Copyright (C) 1992 David L. Brown, Jr. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or | ||
11 | modify it under the terms of the GNU General Public License as | ||
12 | published by the Free Software Foundation; either version 2, or (at | ||
13 | your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, but | ||
16 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; see the file COPYING. If not, write to | ||
22 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | ||
23 | USA. | ||
24 | |||
25 | * | ||
26 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ecc.h,v $ | ||
27 | * $Revision: 1.2 $ | ||
28 | * $Date: 1997/10/05 19:18:11 $ | ||
29 | * | ||
30 | * This file contains the definitions for the | ||
31 | * Reed-Solomon error correction code | ||
32 | * for the QIC-40/80 tape streamer device driver. | ||
33 | */ | ||
34 | |||
35 | #include "../lowlevel/ftape-bsm.h" | ||
36 | |||
37 | #define BAD_CLEAR(entry) ((entry)=0) | ||
38 | #define BAD_SET(entry,sector) ((entry)|=(1<<(sector))) | ||
39 | #define BAD_CHECK(entry,sector) ((entry)&(1<<(sector))) | ||
40 | |||
41 | /* | ||
42 | * Return values for ecc_correct_data: | ||
43 | */ | ||
44 | enum { | ||
45 | ECC_OK, /* Data was correct. */ | ||
46 | ECC_CORRECTED, /* Correctable error in data. */ | ||
47 | ECC_FAILED, /* Could not correct data. */ | ||
48 | }; | ||
49 | |||
50 | /* | ||
51 | * Representation of an in memory segment. MARKED_BAD lists the | ||
52 | * sectors that were marked bad during formatting. If the N-th sector | ||
53 | * in a segment is marked bad, bit 1<<N will be set in MARKED_BAD. | ||
54 | * The sectors should be read in from the disk and packed, as if the | ||
55 | * bad sectors were not there, and the segment just contained fewer | ||
56 | * sectors. READ_SECTORS is a bitmap of errors encountered while | ||
57 | * reading the data. These offsets are relative to the packed data. | ||
58 | * BLOCKS is a count of the sectors not marked bad. This is just to | ||
59 | * prevent having to count the zero bits in MARKED_BAD each time this | ||
60 | * is needed. DATA is the actual sector packed data from (or to) the | ||
61 | * tape. | ||
62 | */ | ||
63 | struct memory_segment { | ||
64 | SectorMap marked_bad; | ||
65 | SectorMap read_bad; | ||
66 | int blocks; | ||
67 | __u8 *data; | ||
68 | SectorMap corrected; | ||
69 | }; | ||
70 | |||
71 | /* | ||
72 | * ecc.c defined global variables: | ||
73 | */ | ||
74 | #ifdef TEST | ||
75 | extern int ftape_ecc_tracing; | ||
76 | #endif | ||
77 | |||
78 | /* | ||
79 | * ecc.c defined global functions: | ||
80 | */ | ||
81 | extern int ftape_ecc_correct_data(struct memory_segment *data); | ||
82 | extern int ftape_ecc_set_segment_parity(struct memory_segment *data); | ||
83 | |||
84 | #endif /* _FTAPE_ECC_H_ */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-format.c b/drivers/char/ftape/lowlevel/ftape-format.c deleted file mode 100644 index 5dd4c59a3f34..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-format.c +++ /dev/null | |||
@@ -1,344 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1997 Claus-Justus Heine. | ||
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 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-format.c,v $ | ||
20 | * $Revision: 1.2.4.1 $ | ||
21 | * $Date: 1997/11/14 16:05:39 $ | ||
22 | * | ||
23 | * This file contains the code to support formatting of floppy | ||
24 | * tape cartridges with the QIC-40/80/3010/3020 floppy-tape | ||
25 | * driver "ftape" for Linux. | ||
26 | */ | ||
27 | |||
28 | #include <linux/string.h> | ||
29 | #include <linux/errno.h> | ||
30 | |||
31 | #include <linux/ftape.h> | ||
32 | #include <linux/qic117.h> | ||
33 | #include "../lowlevel/ftape-tracing.h" | ||
34 | #include "../lowlevel/ftape-io.h" | ||
35 | #include "../lowlevel/ftape-ctl.h" | ||
36 | #include "../lowlevel/ftape-rw.h" | ||
37 | #include "../lowlevel/ftape-ecc.h" | ||
38 | #include "../lowlevel/ftape-bsm.h" | ||
39 | #include "../lowlevel/ftape-format.h" | ||
40 | |||
41 | #if defined(TESTING) | ||
42 | #define FT_FMT_SEGS_PER_BUF 50 | ||
43 | #else | ||
44 | #define FT_FMT_SEGS_PER_BUF (FT_BUFF_SIZE/(4*FT_SECTORS_PER_SEGMENT)) | ||
45 | #endif | ||
46 | |||
47 | static spinlock_t ftape_format_lock; | ||
48 | |||
49 | /* | ||
50 | * first segment of the new buffer | ||
51 | */ | ||
52 | static int switch_segment; | ||
53 | |||
54 | /* | ||
55 | * at most 256 segments fit into one 32 kb buffer. Even TR-1 cartridges have | ||
56 | * more than this many segments per track, so better be careful. | ||
57 | * | ||
58 | * buffer_struct *buff: buffer to store the formatting coordinates in | ||
59 | * int start: starting segment for this buffer. | ||
60 | * int spt: segments per track | ||
61 | * | ||
62 | * Note: segment ids are relative to the start of the track here. | ||
63 | */ | ||
64 | static void setup_format_buffer(buffer_struct *buff, int start, int spt, | ||
65 | __u8 gap3) | ||
66 | { | ||
67 | int to_do = spt - start; | ||
68 | TRACE_FUN(ft_t_flow); | ||
69 | |||
70 | if (to_do > FT_FMT_SEGS_PER_BUF) { | ||
71 | to_do = FT_FMT_SEGS_PER_BUF; | ||
72 | } | ||
73 | buff->ptr = buff->address; | ||
74 | buff->remaining = to_do * FT_SECTORS_PER_SEGMENT; /* # sectors */ | ||
75 | buff->bytes = buff->remaining * 4; /* need 4 bytes per sector */ | ||
76 | buff->gap3 = gap3; | ||
77 | buff->segment_id = start; | ||
78 | buff->next_segment = start + to_do; | ||
79 | if (buff->next_segment >= spt) { | ||
80 | buff->next_segment = 0; /* 0 means: stop runner */ | ||
81 | } | ||
82 | buff->status = waiting; /* tells the isr that it can use | ||
83 | * this buffer | ||
84 | */ | ||
85 | TRACE_EXIT; | ||
86 | } | ||
87 | |||
88 | |||
89 | /* | ||
90 | * start formatting a new track. | ||
91 | */ | ||
92 | int ftape_format_track(const unsigned int track, const __u8 gap3) | ||
93 | { | ||
94 | unsigned long flags; | ||
95 | buffer_struct *tail, *head; | ||
96 | int status; | ||
97 | TRACE_FUN(ft_t_flow); | ||
98 | |||
99 | TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); | ||
100 | if (track & 1) { | ||
101 | if (!(status & QIC_STATUS_AT_EOT)) { | ||
102 | TRACE_CATCH(ftape_seek_to_eot(),); | ||
103 | } | ||
104 | } else { | ||
105 | if (!(status & QIC_STATUS_AT_BOT)) { | ||
106 | TRACE_CATCH(ftape_seek_to_bot(),); | ||
107 | } | ||
108 | } | ||
109 | ftape_abort_operation(); /* this sets ft_head = ft_tail = 0 */ | ||
110 | ftape_set_state(formatting); | ||
111 | |||
112 | TRACE(ft_t_noise, | ||
113 | "Formatting track %d, logical: from segment %d to %d", | ||
114 | track, track * ft_segments_per_track, | ||
115 | (track + 1) * ft_segments_per_track - 1); | ||
116 | |||
117 | /* | ||
118 | * initialize the buffer switching protocol for this track | ||
119 | */ | ||
120 | head = ftape_get_buffer(ft_queue_head); /* tape isn't running yet */ | ||
121 | tail = ftape_get_buffer(ft_queue_tail); /* tape isn't running yet */ | ||
122 | switch_segment = 0; | ||
123 | do { | ||
124 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
125 | setup_format_buffer(tail, switch_segment, | ||
126 | ft_segments_per_track, gap3); | ||
127 | switch_segment = tail->next_segment; | ||
128 | } while ((switch_segment != 0) && | ||
129 | ((tail = ftape_next_buffer(ft_queue_tail)) != head)); | ||
130 | /* go */ | ||
131 | head->status = formatting; | ||
132 | TRACE_CATCH(ftape_seek_head_to_track(track),); | ||
133 | TRACE_CATCH(ftape_command(QIC_LOGICAL_FORWARD),); | ||
134 | spin_lock_irqsave(&ftape_format_lock, flags); | ||
135 | TRACE_CATCH(fdc_setup_formatting(head), restore_flags(flags)); | ||
136 | spin_unlock_irqrestore(&ftape_format_lock, flags); | ||
137 | TRACE_EXIT 0; | ||
138 | } | ||
139 | |||
140 | /* return segment id of segment currently being formatted and do the | ||
141 | * buffer switching stuff. | ||
142 | */ | ||
143 | int ftape_format_status(unsigned int *segment_id) | ||
144 | { | ||
145 | buffer_struct *tail = ftape_get_buffer(ft_queue_tail); | ||
146 | int result; | ||
147 | TRACE_FUN(ft_t_flow); | ||
148 | |||
149 | while (switch_segment != 0 && | ||
150 | ftape_get_buffer(ft_queue_head) != tail) { | ||
151 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
152 | /* need more buffers, first wait for empty buffer | ||
153 | */ | ||
154 | TRACE_CATCH(ftape_wait_segment(formatting),); | ||
155 | /* don't worry for gap3. If we ever hit this piece of code, | ||
156 | * then all buffer already have the correct gap3 set! | ||
157 | */ | ||
158 | setup_format_buffer(tail, switch_segment, | ||
159 | ft_segments_per_track, tail->gap3); | ||
160 | switch_segment = tail->next_segment; | ||
161 | if (switch_segment != 0) { | ||
162 | tail = ftape_next_buffer(ft_queue_tail); | ||
163 | } | ||
164 | } | ||
165 | /* should runner stop ? | ||
166 | */ | ||
167 | if (ft_runner_status == aborting || ft_runner_status == do_abort) { | ||
168 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
169 | TRACE(ft_t_warn, "Error formatting segment %d", | ||
170 | ftape_get_buffer(ft_queue_head)->segment_id); | ||
171 | (void)ftape_abort_operation(); | ||
172 | TRACE_EXIT (head->status != error) ? -EAGAIN : -EIO; | ||
173 | } | ||
174 | /* | ||
175 | * don't care if the timer expires, this is just kind of a | ||
176 | * "select" operation that lets the calling process sleep | ||
177 | * until something has happened | ||
178 | */ | ||
179 | if (fdc_interrupt_wait(5 * FT_SECOND) < 0) { | ||
180 | TRACE(ft_t_noise, "End of track %d at segment %d", | ||
181 | ft_location.track, | ||
182 | ftape_get_buffer(ft_queue_head)->segment_id); | ||
183 | result = 1; /* end of track, unlock module */ | ||
184 | } else { | ||
185 | result = 0; | ||
186 | } | ||
187 | /* | ||
188 | * the calling process should use the seg id to determine | ||
189 | * which parts of the dma buffers can be safely overwritten | ||
190 | * with new data. | ||
191 | */ | ||
192 | *segment_id = ftape_get_buffer(ft_queue_head)->segment_id; | ||
193 | /* | ||
194 | * Internally we start counting segment ids from the start of | ||
195 | * each track when formatting, but externally we keep them | ||
196 | * relative to the start of the tape: | ||
197 | */ | ||
198 | *segment_id += ft_location.track * ft_segments_per_track; | ||
199 | TRACE_EXIT result; | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * The segment id is relative to the start of the tape | ||
204 | */ | ||
205 | int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm) | ||
206 | { | ||
207 | int result; | ||
208 | int verify_done = 0; | ||
209 | TRACE_FUN(ft_t_flow); | ||
210 | |||
211 | TRACE(ft_t_noise, "Verifying segment %d", segment_id); | ||
212 | |||
213 | if (ft_driver_state != verifying) { | ||
214 | TRACE(ft_t_noise, "calling ftape_abort_operation"); | ||
215 | if (ftape_abort_operation() < 0) { | ||
216 | TRACE(ft_t_err, "ftape_abort_operation failed"); | ||
217 | TRACE_EXIT -EIO; | ||
218 | } | ||
219 | } | ||
220 | *bsm = 0x00000000; | ||
221 | ftape_set_state(verifying); | ||
222 | for (;;) { | ||
223 | buffer_struct *tail; | ||
224 | /* | ||
225 | * Allow escape from this loop on signal | ||
226 | */ | ||
227 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
228 | /* | ||
229 | * Search all full buffers for the first matching the | ||
230 | * wanted segment. Clear other buffers on the fly. | ||
231 | */ | ||
232 | tail = ftape_get_buffer(ft_queue_tail); | ||
233 | while (!verify_done && tail->status == done) { | ||
234 | /* | ||
235 | * Allow escape from this loop on signal ! | ||
236 | */ | ||
237 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
238 | if (tail->segment_id == segment_id) { | ||
239 | /* If out buffer is already full, | ||
240 | * return its contents. | ||
241 | */ | ||
242 | TRACE(ft_t_flow, "found segment in cache: %d", | ||
243 | segment_id); | ||
244 | if ((tail->soft_error_map | | ||
245 | tail->hard_error_map) != 0) { | ||
246 | TRACE(ft_t_info,"bsm[%d] = 0x%08lx", | ||
247 | segment_id, | ||
248 | (unsigned long) | ||
249 | (tail->soft_error_map | | ||
250 | tail->hard_error_map)); | ||
251 | *bsm = (tail->soft_error_map | | ||
252 | tail->hard_error_map); | ||
253 | } | ||
254 | verify_done = 1; | ||
255 | } else { | ||
256 | TRACE(ft_t_flow,"zapping segment in cache: %d", | ||
257 | tail->segment_id); | ||
258 | } | ||
259 | tail->status = waiting; | ||
260 | tail = ftape_next_buffer(ft_queue_tail); | ||
261 | } | ||
262 | if (!verify_done && tail->status == verifying) { | ||
263 | if (tail->segment_id == segment_id) { | ||
264 | switch(ftape_wait_segment(verifying)) { | ||
265 | case 0: | ||
266 | break; | ||
267 | case -EINTR: | ||
268 | TRACE_ABORT(-EINTR, ft_t_warn, | ||
269 | "interrupted by " | ||
270 | "non-blockable signal"); | ||
271 | break; | ||
272 | default: | ||
273 | ftape_abort_operation(); | ||
274 | ftape_set_state(verifying); | ||
275 | /* be picky */ | ||
276 | TRACE_ABORT(-EIO, ft_t_warn, | ||
277 | "wait_segment failed"); | ||
278 | } | ||
279 | } else { | ||
280 | /* We're reading the wrong segment, | ||
281 | * stop runner. | ||
282 | */ | ||
283 | TRACE(ft_t_noise, "verifying wrong segment"); | ||
284 | ftape_abort_operation(); | ||
285 | ftape_set_state(verifying); | ||
286 | } | ||
287 | } | ||
288 | /* should runner stop ? | ||
289 | */ | ||
290 | if (ft_runner_status == aborting) { | ||
291 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
292 | if (head->status == error || | ||
293 | head->status == verifying) { | ||
294 | /* no data or overrun error */ | ||
295 | head->status = waiting; | ||
296 | } | ||
297 | TRACE_CATCH(ftape_dumb_stop(),); | ||
298 | } else { | ||
299 | /* If just passed last segment on tape: wait | ||
300 | * for BOT or EOT mark. Sets ft_runner_status to | ||
301 | * idle if at lEOT and successful | ||
302 | */ | ||
303 | TRACE_CATCH(ftape_handle_logical_eot(),); | ||
304 | } | ||
305 | if (verify_done) { | ||
306 | TRACE_EXIT 0; | ||
307 | } | ||
308 | /* Now at least one buffer is idle! | ||
309 | * Restart runner & tape if needed. | ||
310 | */ | ||
311 | /* We could optimize the following a little bit. We know that | ||
312 | * the bad sector map is empty. | ||
313 | */ | ||
314 | tail = ftape_get_buffer(ft_queue_tail); | ||
315 | if (tail->status == waiting) { | ||
316 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
317 | |||
318 | ftape_setup_new_segment(head, segment_id, -1); | ||
319 | ftape_calc_next_cluster(head); | ||
320 | if (ft_runner_status == idle) { | ||
321 | result = ftape_start_tape(segment_id, | ||
322 | head->sector_offset); | ||
323 | switch(result) { | ||
324 | case 0: | ||
325 | break; | ||
326 | case -ETIME: | ||
327 | case -EINTR: | ||
328 | TRACE_ABORT(result, ft_t_err, "Error: " | ||
329 | "segment %d unreachable", | ||
330 | segment_id); | ||
331 | break; | ||
332 | default: | ||
333 | *bsm = EMPTY_SEGMENT; | ||
334 | TRACE_EXIT 0; | ||
335 | break; | ||
336 | } | ||
337 | } | ||
338 | head->status = verifying; | ||
339 | fdc_setup_read_write(head, FDC_VERIFY); | ||
340 | } | ||
341 | } | ||
342 | /* not reached */ | ||
343 | TRACE_EXIT -EIO; | ||
344 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-format.h b/drivers/char/ftape/lowlevel/ftape-format.h deleted file mode 100644 index f15161566643..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-format.h +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | #ifndef _FTAPE_FORMAT_H | ||
2 | #define _FTAPE_FORMAT_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996-1997 Claus-Justus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-format.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:18:13 $ | ||
25 | * | ||
26 | * This file contains the low level definitions for the | ||
27 | * formatting support for the QIC-40/80/3010/3020 floppy-tape | ||
28 | * driver "ftape" for Linux. | ||
29 | */ | ||
30 | |||
31 | #ifdef __KERNEL__ | ||
32 | extern int ftape_format_track(const unsigned int track, const __u8 gap3); | ||
33 | extern int ftape_format_status(unsigned int *segment_id); | ||
34 | extern int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm); | ||
35 | #endif /* __KERNEL__ */ | ||
36 | |||
37 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-init.c b/drivers/char/ftape/lowlevel/ftape-init.c deleted file mode 100644 index 4998132a81d1..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-init.c +++ /dev/null | |||
@@ -1,160 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-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 | * This file contains the code that interfaces the kernel | ||
21 | * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/fs.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/signal.h> | ||
29 | #include <linux/major.h> | ||
30 | |||
31 | #include <linux/ftape.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/qic117.h> | ||
34 | #ifdef CONFIG_ZFTAPE | ||
35 | #include <linux/zftape.h> | ||
36 | #endif | ||
37 | |||
38 | #include "../lowlevel/ftape-init.h" | ||
39 | #include "../lowlevel/ftape-io.h" | ||
40 | #include "../lowlevel/ftape-read.h" | ||
41 | #include "../lowlevel/ftape-write.h" | ||
42 | #include "../lowlevel/ftape-ctl.h" | ||
43 | #include "../lowlevel/ftape-rw.h" | ||
44 | #include "../lowlevel/fdc-io.h" | ||
45 | #include "../lowlevel/ftape-buffer.h" | ||
46 | #include "../lowlevel/ftape-proc.h" | ||
47 | #include "../lowlevel/ftape-tracing.h" | ||
48 | |||
49 | |||
50 | #if defined(MODULE) && !defined(CONFIG_FT_NO_TRACE_AT_ALL) | ||
51 | static int ft_tracing = -1; | ||
52 | #endif | ||
53 | |||
54 | |||
55 | /* Called by modules package when installing the driver | ||
56 | * or by kernel during the initialization phase | ||
57 | */ | ||
58 | static int __init ftape_init(void) | ||
59 | { | ||
60 | TRACE_FUN(ft_t_flow); | ||
61 | |||
62 | #ifdef MODULE | ||
63 | #ifndef CONFIG_FT_NO_TRACE_AT_ALL | ||
64 | if (ft_tracing != -1) { | ||
65 | ftape_tracing = ft_tracing; | ||
66 | } | ||
67 | #endif | ||
68 | printk(KERN_INFO FTAPE_VERSION "\n"); | ||
69 | if (TRACE_LEVEL >= ft_t_info) { | ||
70 | printk( | ||
71 | KERN_INFO "(c) 1993-1996 Bas Laarhoven (bas@vimec.nl)\n" | ||
72 | KERN_INFO "(c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no)\n" | ||
73 | KERN_INFO "(c) 1996-1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" | ||
74 | KERN_INFO "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives\n"); | ||
75 | } | ||
76 | #else /* !MODULE */ | ||
77 | /* print a short no-nonsense boot message */ | ||
78 | printk(KERN_INFO FTAPE_VERSION "\n"); | ||
79 | #endif /* MODULE */ | ||
80 | TRACE(ft_t_info, "installing QIC-117 floppy tape hardware drive ... "); | ||
81 | TRACE(ft_t_info, "ftape_init @ 0x%p", ftape_init); | ||
82 | /* Allocate the DMA buffers. They are deallocated at cleanup() time. | ||
83 | */ | ||
84 | #ifdef TESTING | ||
85 | #ifdef MODULE | ||
86 | while (ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS) < 0) { | ||
87 | ftape_sleep(FT_SECOND/20); | ||
88 | if (signal_pending(current)) { | ||
89 | (void)ftape_set_nr_buffers(0); | ||
90 | TRACE(ft_t_bug, | ||
91 | "Killed by signal while allocating buffers."); | ||
92 | TRACE_ABORT(-EINTR, | ||
93 | ft_t_bug, "Free up memory and retry"); | ||
94 | } | ||
95 | } | ||
96 | #else | ||
97 | TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS), | ||
98 | (void)ftape_set_nr_buffers(0)); | ||
99 | #endif | ||
100 | #else | ||
101 | TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS), | ||
102 | (void)ftape_set_nr_buffers(0)); | ||
103 | #endif | ||
104 | ft_drive_sel = -1; | ||
105 | ft_failure = 1; /* inhibit any operation but open */ | ||
106 | ftape_udelay_calibrate(); /* must be before fdc_wait_calibrate ! */ | ||
107 | fdc_wait_calibrate(); | ||
108 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) | ||
109 | (void)ftape_proc_init(); | ||
110 | #endif | ||
111 | #ifdef CONFIG_ZFTAPE | ||
112 | (void)zft_init(); | ||
113 | #endif | ||
114 | TRACE_EXIT 0; | ||
115 | } | ||
116 | |||
117 | module_param(ft_fdc_base, uint, 0); | ||
118 | MODULE_PARM_DESC(ft_fdc_base, "Base address of FDC controller."); | ||
119 | module_param(ft_fdc_irq, uint, 0); | ||
120 | MODULE_PARM_DESC(ft_fdc_irq, "IRQ (interrupt channel) to use."); | ||
121 | module_param(ft_fdc_dma, uint, 0); | ||
122 | MODULE_PARM_DESC(ft_fdc_dma, "DMA channel to use."); | ||
123 | module_param(ft_fdc_threshold, uint, 0); | ||
124 | MODULE_PARM_DESC(ft_fdc_threshold, "Threshold of the FDC Fifo."); | ||
125 | module_param(ft_fdc_rate_limit, uint, 0); | ||
126 | MODULE_PARM_DESC(ft_fdc_rate_limit, "Maximal data rate for FDC."); | ||
127 | module_param(ft_probe_fc10, bool, 0); | ||
128 | MODULE_PARM_DESC(ft_probe_fc10, | ||
129 | "If non-zero, probe for a Colorado FC-10/FC-20 controller."); | ||
130 | module_param(ft_mach2, bool, 0); | ||
131 | MODULE_PARM_DESC(ft_mach2, | ||
132 | "If non-zero, probe for a Mountain MACH-2 controller."); | ||
133 | #if defined(MODULE) && !defined(CONFIG_FT_NO_TRACE_AT_ALL) | ||
134 | module_param(ft_tracing, int, 0644); | ||
135 | MODULE_PARM_DESC(ft_tracing, | ||
136 | "Amount of debugging output, 0 <= tracing <= 8, default 3."); | ||
137 | #endif | ||
138 | |||
139 | MODULE_AUTHOR( | ||
140 | "(c) 1993-1996 Bas Laarhoven (bas@vimec.nl), " | ||
141 | "(c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no), " | ||
142 | "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)"); | ||
143 | MODULE_DESCRIPTION( | ||
144 | "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives."); | ||
145 | MODULE_LICENSE("GPL"); | ||
146 | |||
147 | static void __exit ftape_exit(void) | ||
148 | { | ||
149 | TRACE_FUN(ft_t_flow); | ||
150 | |||
151 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) | ||
152 | ftape_proc_destroy(); | ||
153 | #endif | ||
154 | (void)ftape_set_nr_buffers(0); | ||
155 | printk(KERN_INFO "ftape: unloaded.\n"); | ||
156 | TRACE_EXIT; | ||
157 | } | ||
158 | |||
159 | module_init(ftape_init); | ||
160 | module_exit(ftape_exit); | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-init.h b/drivers/char/ftape/lowlevel/ftape-init.h deleted file mode 100644 index 99a7b8ab086f..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-init.h +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | #ifndef _FTAPE_INIT_H | ||
2 | #define _FTAPE_INIT_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-init.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:16 $ | ||
26 | * | ||
27 | * This file contains the definitions for the interface to | ||
28 | * the Linux kernel for floppy tape driver ftape. | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/linkage.h> | ||
33 | #include <linux/signal.h> | ||
34 | |||
35 | #define _NEVER_BLOCK (sigmask(SIGKILL) | sigmask(SIGSTOP)) | ||
36 | #define _DONT_BLOCK (_NEVER_BLOCK | sigmask(SIGINT)) | ||
37 | #define _DO_BLOCK (sigmask(SIGPIPE)) | ||
38 | |||
39 | #ifndef QIC117_TAPE_MAJOR | ||
40 | #define QIC117_TAPE_MAJOR 27 | ||
41 | #endif | ||
42 | |||
43 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-io.c b/drivers/char/ftape/lowlevel/ftape-io.c deleted file mode 100644 index 259015aeff55..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-io.c +++ /dev/null | |||
@@ -1,992 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
3 | * (C) 1996 Kai Harrekilde-Petersen, | ||
4 | * (C) 1997 Claus-Justus Heine. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; see the file COPYING. If not, write to | ||
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | |||
20 | * | ||
21 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-io.c,v $ | ||
22 | * $Revision: 1.4 $ | ||
23 | * $Date: 1997/11/11 14:02:36 $ | ||
24 | * | ||
25 | * This file contains the general control functions for the | ||
26 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
27 | */ | ||
28 | |||
29 | #include <linux/errno.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <linux/ioctl.h> | ||
34 | #include <linux/mtio.h> | ||
35 | #include <linux/delay.h> | ||
36 | |||
37 | #include <linux/ftape.h> | ||
38 | #include <linux/qic117.h> | ||
39 | #include "../lowlevel/ftape-tracing.h" | ||
40 | #include "../lowlevel/fdc-io.h" | ||
41 | #include "../lowlevel/ftape-io.h" | ||
42 | #include "../lowlevel/ftape-ctl.h" | ||
43 | #include "../lowlevel/ftape-rw.h" | ||
44 | #include "../lowlevel/ftape-write.h" | ||
45 | #include "../lowlevel/ftape-read.h" | ||
46 | #include "../lowlevel/ftape-init.h" | ||
47 | #include "../lowlevel/ftape-calibr.h" | ||
48 | |||
49 | /* Global vars. | ||
50 | */ | ||
51 | /* NOTE: sectors start numbering at 1, all others at 0 ! */ | ||
52 | ft_timeout_table ftape_timeout; | ||
53 | unsigned int ftape_tape_len; | ||
54 | volatile qic117_cmd_t ftape_current_command; | ||
55 | const struct qic117_command_table qic117_cmds[] = QIC117_COMMANDS; | ||
56 | int ftape_might_be_off_track; | ||
57 | |||
58 | /* Local vars. | ||
59 | */ | ||
60 | static int diagnostic_mode; | ||
61 | static unsigned int ftape_udelay_count; | ||
62 | static unsigned int ftape_udelay_time; | ||
63 | |||
64 | void ftape_udelay(unsigned int usecs) | ||
65 | { | ||
66 | volatile int count = (ftape_udelay_count * usecs + | ||
67 | ftape_udelay_count - 1) / ftape_udelay_time; | ||
68 | volatile int i; | ||
69 | |||
70 | while (count-- > 0) { | ||
71 | for (i = 0; i < 20; ++i); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | void ftape_udelay_calibrate(void) | ||
76 | { | ||
77 | ftape_calibrate("ftape_udelay", | ||
78 | ftape_udelay, &ftape_udelay_count, &ftape_udelay_time); | ||
79 | } | ||
80 | |||
81 | /* Delay (msec) routine. | ||
82 | */ | ||
83 | void ftape_sleep(unsigned int time) | ||
84 | { | ||
85 | TRACE_FUN(ft_t_any); | ||
86 | |||
87 | time *= 1000; /* msecs -> usecs */ | ||
88 | if (time < FT_USPT) { | ||
89 | /* Time too small for scheduler, do a busy wait ! */ | ||
90 | ftape_udelay(time); | ||
91 | } else { | ||
92 | long timeout; | ||
93 | unsigned long flags; | ||
94 | unsigned int ticks = (time + FT_USPT - 1) / FT_USPT; | ||
95 | |||
96 | TRACE(ft_t_any, "%d msec, %d ticks", time/1000, ticks); | ||
97 | timeout = ticks; | ||
98 | save_flags(flags); | ||
99 | sti(); | ||
100 | msleep_interruptible(jiffies_to_msecs(timeout)); | ||
101 | /* Mmm. Isn't current->blocked == 0xffffffff ? | ||
102 | */ | ||
103 | if (signal_pending(current)) { | ||
104 | TRACE(ft_t_err, "awoken by non-blocked signal :-("); | ||
105 | } | ||
106 | restore_flags(flags); | ||
107 | } | ||
108 | TRACE_EXIT; | ||
109 | } | ||
110 | |||
111 | /* send a command or parameter to the drive | ||
112 | * Generates # of step pulses. | ||
113 | */ | ||
114 | static inline int ft_send_to_drive(int arg) | ||
115 | { | ||
116 | /* Always wait for a command_timeout period to separate | ||
117 | * individuals commands and/or parameters. | ||
118 | */ | ||
119 | ftape_sleep(3 * FT_MILLISECOND); | ||
120 | /* Keep cylinder nr within range, step towards home if possible. | ||
121 | */ | ||
122 | if (ftape_current_cylinder >= arg) { | ||
123 | return fdc_seek(ftape_current_cylinder - arg); | ||
124 | } else { | ||
125 | return fdc_seek(ftape_current_cylinder + arg); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | /* forward */ int ftape_report_raw_drive_status(int *status); | ||
130 | |||
131 | static int ft_check_cmd_restrictions(qic117_cmd_t command) | ||
132 | { | ||
133 | int status = -1; | ||
134 | TRACE_FUN(ft_t_any); | ||
135 | |||
136 | TRACE(ft_t_flow, "%s", qic117_cmds[command].name); | ||
137 | /* A new motion command during an uninterruptible (motion) | ||
138 | * command requires a ready status before the new command can | ||
139 | * be issued. Otherwise a new motion command needs to be | ||
140 | * checked against required status. | ||
141 | */ | ||
142 | if (qic117_cmds[command].cmd_type == motion && | ||
143 | qic117_cmds[ftape_current_command].non_intr) { | ||
144 | ftape_report_raw_drive_status(&status); | ||
145 | if ((status & QIC_STATUS_READY) == 0) { | ||
146 | TRACE(ft_t_noise, | ||
147 | "motion cmd (%d) during non-intr cmd (%d)", | ||
148 | command, ftape_current_command); | ||
149 | TRACE(ft_t_noise, "waiting until drive gets ready"); | ||
150 | ftape_ready_wait(ftape_timeout.seek, | ||
151 | &status); | ||
152 | } | ||
153 | } | ||
154 | if (qic117_cmds[command].mask != 0) { | ||
155 | __u8 difference; | ||
156 | /* Some commands do require a certain status: | ||
157 | */ | ||
158 | if (status == -1) { /* not yet set */ | ||
159 | ftape_report_raw_drive_status(&status); | ||
160 | } | ||
161 | difference = ((status ^ qic117_cmds[command].state) & | ||
162 | qic117_cmds[command].mask); | ||
163 | /* Wait until the drive gets | ||
164 | * ready. This may last forever if | ||
165 | * the drive never gets ready... | ||
166 | */ | ||
167 | while ((difference & QIC_STATUS_READY) != 0) { | ||
168 | TRACE(ft_t_noise, "command %d issued while not ready", | ||
169 | command); | ||
170 | TRACE(ft_t_noise, "waiting until drive gets ready"); | ||
171 | if (ftape_ready_wait(ftape_timeout.seek, | ||
172 | &status) == -EINTR) { | ||
173 | /* Bail out on signal ! | ||
174 | */ | ||
175 | TRACE_ABORT(-EINTR, ft_t_warn, | ||
176 | "interrupted by non-blockable signal"); | ||
177 | } | ||
178 | difference = ((status ^ qic117_cmds[command].state) & | ||
179 | qic117_cmds[command].mask); | ||
180 | } | ||
181 | while ((difference & QIC_STATUS_ERROR) != 0) { | ||
182 | int err; | ||
183 | qic117_cmd_t cmd; | ||
184 | |||
185 | TRACE(ft_t_noise, | ||
186 | "command %d issued while error pending", | ||
187 | command); | ||
188 | TRACE(ft_t_noise, "clearing error status"); | ||
189 | ftape_report_error(&err, &cmd, 1); | ||
190 | ftape_report_raw_drive_status(&status); | ||
191 | difference = ((status ^ qic117_cmds[command].state) & | ||
192 | qic117_cmds[command].mask); | ||
193 | if ((difference & QIC_STATUS_ERROR) != 0) { | ||
194 | /* Bail out on fatal signal ! | ||
195 | */ | ||
196 | FT_SIGNAL_EXIT(_NEVER_BLOCK); | ||
197 | } | ||
198 | } | ||
199 | if (difference) { | ||
200 | /* Any remaining difference can't be solved | ||
201 | * here. | ||
202 | */ | ||
203 | if (difference & (QIC_STATUS_CARTRIDGE_PRESENT | | ||
204 | QIC_STATUS_NEW_CARTRIDGE | | ||
205 | QIC_STATUS_REFERENCED)) { | ||
206 | TRACE(ft_t_warn, | ||
207 | "Fatal: tape removed or reinserted !"); | ||
208 | ft_failure = 1; | ||
209 | } else { | ||
210 | TRACE(ft_t_err, "wrong state: 0x%02x should be: 0x%02x", | ||
211 | status & qic117_cmds[command].mask, | ||
212 | qic117_cmds[command].state); | ||
213 | } | ||
214 | TRACE_EXIT -EIO; | ||
215 | } | ||
216 | if (~status & QIC_STATUS_READY & qic117_cmds[command].mask) { | ||
217 | TRACE_ABORT(-EBUSY, ft_t_err, "Bad: still busy!"); | ||
218 | } | ||
219 | } | ||
220 | TRACE_EXIT 0; | ||
221 | } | ||
222 | |||
223 | /* Issue a tape command: | ||
224 | */ | ||
225 | int ftape_command(qic117_cmd_t command) | ||
226 | { | ||
227 | int result = 0; | ||
228 | static int level; | ||
229 | TRACE_FUN(ft_t_any); | ||
230 | |||
231 | if ((unsigned int)command > NR_ITEMS(qic117_cmds)) { | ||
232 | /* This is a bug we'll want to know about too. | ||
233 | */ | ||
234 | TRACE_ABORT(-EIO, ft_t_bug, "bug - bad command: %d", command); | ||
235 | } | ||
236 | if (++level > 5) { /* This is a bug we'll want to know about. */ | ||
237 | --level; | ||
238 | TRACE_ABORT(-EIO, ft_t_bug, "bug - recursion for command: %d", | ||
239 | command); | ||
240 | } | ||
241 | /* disable logging and restriction check for some commands, | ||
242 | * check all other commands that have a prescribed starting | ||
243 | * status. | ||
244 | */ | ||
245 | if (diagnostic_mode) { | ||
246 | TRACE(ft_t_flow, "diagnostic command %d", command); | ||
247 | } else if (command == QIC_REPORT_DRIVE_STATUS || | ||
248 | command == QIC_REPORT_NEXT_BIT) { | ||
249 | TRACE(ft_t_any, "%s", qic117_cmds[command].name); | ||
250 | } else { | ||
251 | TRACE_CATCH(ft_check_cmd_restrictions(command), --level); | ||
252 | } | ||
253 | /* Now all conditions are met or result was < 0. | ||
254 | */ | ||
255 | result = ft_send_to_drive((unsigned int)command); | ||
256 | if (qic117_cmds[command].cmd_type == motion && | ||
257 | command != QIC_LOGICAL_FORWARD && command != QIC_STOP_TAPE) { | ||
258 | ft_location.known = 0; | ||
259 | } | ||
260 | ftape_current_command = command; | ||
261 | --level; | ||
262 | TRACE_EXIT result; | ||
263 | } | ||
264 | |||
265 | /* Send a tape command parameter: | ||
266 | * Generates command # of step pulses. | ||
267 | * Skips tape-status call ! | ||
268 | */ | ||
269 | int ftape_parameter(unsigned int parameter) | ||
270 | { | ||
271 | TRACE_FUN(ft_t_any); | ||
272 | |||
273 | TRACE(ft_t_flow, "called with parameter = %d", parameter); | ||
274 | TRACE_EXIT ft_send_to_drive(parameter + 2); | ||
275 | } | ||
276 | |||
277 | /* Wait for the drive to get ready. | ||
278 | * timeout time in milli-seconds | ||
279 | * Returned status is valid if result != -EIO | ||
280 | * | ||
281 | * Should we allow to be killed by SIGINT? (^C) | ||
282 | * Would be nice at least for large timeouts. | ||
283 | */ | ||
284 | int ftape_ready_wait(unsigned int timeout, int *status) | ||
285 | { | ||
286 | unsigned long t0; | ||
287 | unsigned int poll_delay; | ||
288 | int signal_retries; | ||
289 | TRACE_FUN(ft_t_any); | ||
290 | |||
291 | /* the following ** REALLY ** reduces the system load when | ||
292 | * e.g. one simply rewinds or retensions. The tape is slow | ||
293 | * anyway. It is really not necessary to detect error | ||
294 | * conditions with 1/10 seconds granularity | ||
295 | * | ||
296 | * On my AMD 133MHZ 486: 100 ms: 23% system load | ||
297 | * 1 sec: 5% | ||
298 | * 5 sec: 0.6%, yeah | ||
299 | */ | ||
300 | if (timeout <= FT_SECOND) { | ||
301 | poll_delay = 100 * FT_MILLISECOND; | ||
302 | signal_retries = 20; /* two seconds */ | ||
303 | } else if (timeout < 20 * FT_SECOND) { | ||
304 | TRACE(ft_t_flow, "setting poll delay to 1 second"); | ||
305 | poll_delay = FT_SECOND; | ||
306 | signal_retries = 2; /* two seconds */ | ||
307 | } else { | ||
308 | TRACE(ft_t_flow, "setting poll delay to 5 seconds"); | ||
309 | poll_delay = 5 * FT_SECOND; | ||
310 | signal_retries = 1; /* five seconds */ | ||
311 | } | ||
312 | for (;;) { | ||
313 | t0 = jiffies; | ||
314 | TRACE_CATCH(ftape_report_raw_drive_status(status),); | ||
315 | if (*status & QIC_STATUS_READY) { | ||
316 | TRACE_EXIT 0; | ||
317 | } | ||
318 | if (!signal_retries--) { | ||
319 | FT_SIGNAL_EXIT(_NEVER_BLOCK); | ||
320 | } | ||
321 | if ((int)timeout >= 0) { | ||
322 | /* this will fail when jiffies wraps around about | ||
323 | * once every year :-) | ||
324 | */ | ||
325 | timeout -= ((jiffies - t0) * FT_SECOND) / HZ; | ||
326 | if (timeout <= 0) { | ||
327 | TRACE_ABORT(-ETIME, ft_t_err, "timeout"); | ||
328 | } | ||
329 | ftape_sleep(poll_delay); | ||
330 | timeout -= poll_delay; | ||
331 | } else { | ||
332 | ftape_sleep(poll_delay); | ||
333 | } | ||
334 | } | ||
335 | TRACE_EXIT -ETIME; | ||
336 | } | ||
337 | |||
338 | /* Issue command and wait up to timeout milli seconds for drive ready | ||
339 | */ | ||
340 | int ftape_command_wait(qic117_cmd_t command, unsigned int timeout, int *status) | ||
341 | { | ||
342 | int result; | ||
343 | |||
344 | /* Drive should be ready, issue command | ||
345 | */ | ||
346 | result = ftape_command(command); | ||
347 | if (result >= 0) { | ||
348 | result = ftape_ready_wait(timeout, status); | ||
349 | } | ||
350 | return result; | ||
351 | } | ||
352 | |||
353 | static int ftape_parameter_wait(unsigned int parm, unsigned int timeout, int *status) | ||
354 | { | ||
355 | int result; | ||
356 | |||
357 | /* Drive should be ready, issue command | ||
358 | */ | ||
359 | result = ftape_parameter(parm); | ||
360 | if (result >= 0) { | ||
361 | result = ftape_ready_wait(timeout, status); | ||
362 | } | ||
363 | return result; | ||
364 | } | ||
365 | |||
366 | /*-------------------------------------------------------------------------- | ||
367 | * Report operations | ||
368 | */ | ||
369 | |||
370 | /* Query the drive about its status. The command is sent and | ||
371 | result_length bits of status are returned (2 extra bits are read | ||
372 | for start and stop). */ | ||
373 | |||
374 | int ftape_report_operation(int *status, | ||
375 | qic117_cmd_t command, | ||
376 | int result_length) | ||
377 | { | ||
378 | int i, st3; | ||
379 | unsigned int t0; | ||
380 | unsigned int dt; | ||
381 | TRACE_FUN(ft_t_any); | ||
382 | |||
383 | TRACE_CATCH(ftape_command(command),); | ||
384 | t0 = ftape_timestamp(); | ||
385 | i = 0; | ||
386 | do { | ||
387 | ++i; | ||
388 | ftape_sleep(3 * FT_MILLISECOND); /* see remark below */ | ||
389 | TRACE_CATCH(fdc_sense_drive_status(&st3),); | ||
390 | dt = ftape_timediff(t0, ftape_timestamp()); | ||
391 | /* Ack should be asserted within Ttimout + Tack = 6 msec. | ||
392 | * Looks like some drives fail to do this so extend this | ||
393 | * period to 300 msec. | ||
394 | */ | ||
395 | } while (!(st3 & ST3_TRACK_0) && dt < 300000); | ||
396 | if (!(st3 & ST3_TRACK_0)) { | ||
397 | TRACE(ft_t_err, | ||
398 | "No acknowledge after %u msec. (%i iter)", dt / 1000, i); | ||
399 | TRACE_ABORT(-EIO, ft_t_err, "timeout on Acknowledge"); | ||
400 | } | ||
401 | /* dt may be larger than expected because of other tasks | ||
402 | * scheduled while we were sleeping. | ||
403 | */ | ||
404 | if (i > 1 && dt > 6000) { | ||
405 | TRACE(ft_t_err, "Acknowledge after %u msec. (%i iter)", | ||
406 | dt / 1000, i); | ||
407 | } | ||
408 | *status = 0; | ||
409 | for (i = 0; i < result_length + 1; i++) { | ||
410 | TRACE_CATCH(ftape_command(QIC_REPORT_NEXT_BIT),); | ||
411 | TRACE_CATCH(fdc_sense_drive_status(&st3),); | ||
412 | if (i < result_length) { | ||
413 | *status |= ((st3 & ST3_TRACK_0) ? 1 : 0) << i; | ||
414 | } else if ((st3 & ST3_TRACK_0) == 0) { | ||
415 | TRACE_ABORT(-EIO, ft_t_err, "missing status stop bit"); | ||
416 | } | ||
417 | } | ||
418 | /* this command will put track zero and index back into normal state */ | ||
419 | (void)ftape_command(QIC_REPORT_NEXT_BIT); | ||
420 | TRACE_EXIT 0; | ||
421 | } | ||
422 | |||
423 | /* Report the current drive status. */ | ||
424 | |||
425 | int ftape_report_raw_drive_status(int *status) | ||
426 | { | ||
427 | int result; | ||
428 | int count = 0; | ||
429 | TRACE_FUN(ft_t_any); | ||
430 | |||
431 | do { | ||
432 | result = ftape_report_operation(status, | ||
433 | QIC_REPORT_DRIVE_STATUS, 8); | ||
434 | } while (result < 0 && ++count <= 3); | ||
435 | if (result < 0) { | ||
436 | TRACE_ABORT(-EIO, ft_t_err, | ||
437 | "report_operation failed after %d trials", count); | ||
438 | } | ||
439 | if ((*status & 0xff) == 0xff) { | ||
440 | TRACE_ABORT(-EIO, ft_t_err, | ||
441 | "impossible drive status 0xff"); | ||
442 | } | ||
443 | if (*status & QIC_STATUS_READY) { | ||
444 | ftape_current_command = QIC_NO_COMMAND; /* completed */ | ||
445 | } | ||
446 | ft_last_status.status.drive_status = (__u8)(*status & 0xff); | ||
447 | TRACE_EXIT 0; | ||
448 | } | ||
449 | |||
450 | int ftape_report_drive_status(int *status) | ||
451 | { | ||
452 | TRACE_FUN(ft_t_any); | ||
453 | |||
454 | TRACE_CATCH(ftape_report_raw_drive_status(status),); | ||
455 | if (*status & QIC_STATUS_NEW_CARTRIDGE || | ||
456 | !(*status & QIC_STATUS_CARTRIDGE_PRESENT)) { | ||
457 | ft_failure = 1; /* will inhibit further operations */ | ||
458 | TRACE_EXIT -EIO; | ||
459 | } | ||
460 | if (*status & QIC_STATUS_READY && *status & QIC_STATUS_ERROR) { | ||
461 | /* Let caller handle all errors */ | ||
462 | TRACE_ABORT(1, ft_t_warn, "warning: error status set!"); | ||
463 | } | ||
464 | TRACE_EXIT 0; | ||
465 | } | ||
466 | |||
467 | int ftape_report_error(unsigned int *error, | ||
468 | qic117_cmd_t *command, int report) | ||
469 | { | ||
470 | static const ftape_error ftape_errors[] = QIC117_ERRORS; | ||
471 | int code; | ||
472 | TRACE_FUN(ft_t_any); | ||
473 | |||
474 | TRACE_CATCH(ftape_report_operation(&code, QIC_REPORT_ERROR_CODE, 16),); | ||
475 | *error = (unsigned int)(code & 0xff); | ||
476 | *command = (qic117_cmd_t)((code>>8)&0xff); | ||
477 | /* remember hardware status, maybe useful for status ioctls | ||
478 | */ | ||
479 | ft_last_error.error.command = (__u8)*command; | ||
480 | ft_last_error.error.error = (__u8)*error; | ||
481 | if (!report) { | ||
482 | TRACE_EXIT 0; | ||
483 | } | ||
484 | if (*error == 0) { | ||
485 | TRACE_ABORT(0, ft_t_info, "No error"); | ||
486 | } | ||
487 | TRACE(ft_t_info, "errorcode: %d", *error); | ||
488 | if (*error < NR_ITEMS(ftape_errors)) { | ||
489 | TRACE(ft_t_noise, "%sFatal ERROR:", | ||
490 | (ftape_errors[*error].fatal ? "" : "Non-")); | ||
491 | TRACE(ft_t_noise, "%s ...", ftape_errors[*error].message); | ||
492 | } else { | ||
493 | TRACE(ft_t_noise, "Unknown ERROR !"); | ||
494 | } | ||
495 | if ((unsigned int)*command < NR_ITEMS(qic117_cmds) && | ||
496 | qic117_cmds[*command].name != NULL) { | ||
497 | TRACE(ft_t_noise, "... caused by command \'%s\'", | ||
498 | qic117_cmds[*command].name); | ||
499 | } else { | ||
500 | TRACE(ft_t_noise, "... caused by unknown command %d", | ||
501 | *command); | ||
502 | } | ||
503 | TRACE_EXIT 0; | ||
504 | } | ||
505 | |||
506 | int ftape_report_configuration(qic_model *model, | ||
507 | unsigned int *rate, | ||
508 | int *qic_std, | ||
509 | int *tape_len) | ||
510 | { | ||
511 | int result; | ||
512 | int config; | ||
513 | int status; | ||
514 | static const unsigned int qic_rates[ 4] = { 250, 2000, 500, 1000 }; | ||
515 | TRACE_FUN(ft_t_any); | ||
516 | |||
517 | result = ftape_report_operation(&config, | ||
518 | QIC_REPORT_DRIVE_CONFIGURATION, 8); | ||
519 | if (result < 0) { | ||
520 | ft_last_status.status.drive_config = (__u8)0x00; | ||
521 | *model = prehistoric; | ||
522 | *rate = 500; | ||
523 | *qic_std = QIC_TAPE_QIC40; | ||
524 | *tape_len = 205; | ||
525 | TRACE_EXIT 0; | ||
526 | } else { | ||
527 | ft_last_status.status.drive_config = (__u8)(config & 0xff); | ||
528 | } | ||
529 | *rate = qic_rates[(config & QIC_CONFIG_RATE_MASK) >> QIC_CONFIG_RATE_SHIFT]; | ||
530 | result = ftape_report_operation(&status, QIC_REPORT_TAPE_STATUS, 8); | ||
531 | if (result < 0) { | ||
532 | ft_last_status.status.tape_status = (__u8)0x00; | ||
533 | /* pre- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is valid. | ||
534 | */ | ||
535 | *qic_std = (config & QIC_CONFIG_80) ? | ||
536 | QIC_TAPE_QIC80 : QIC_TAPE_QIC40; | ||
537 | /* ?? how's about 425ft tapes? */ | ||
538 | *tape_len = (config & QIC_CONFIG_LONG) ? 307 : 0; | ||
539 | *model = pre_qic117c; | ||
540 | result = 0; | ||
541 | } else { | ||
542 | ft_last_status.status.tape_status = (__u8)(status & 0xff); | ||
543 | *model = post_qic117b; | ||
544 | TRACE(ft_t_any, "report tape status result = %02x", status); | ||
545 | /* post- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is | ||
546 | * invalid. | ||
547 | */ | ||
548 | switch (status & QIC_TAPE_STD_MASK) { | ||
549 | case QIC_TAPE_QIC40: | ||
550 | case QIC_TAPE_QIC80: | ||
551 | case QIC_TAPE_QIC3020: | ||
552 | case QIC_TAPE_QIC3010: | ||
553 | *qic_std = status & QIC_TAPE_STD_MASK; | ||
554 | break; | ||
555 | default: | ||
556 | *qic_std = -1; | ||
557 | break; | ||
558 | } | ||
559 | switch (status & QIC_TAPE_LEN_MASK) { | ||
560 | case QIC_TAPE_205FT: | ||
561 | /* 205 or 425+ ft 550 Oe tape */ | ||
562 | *tape_len = 0; | ||
563 | break; | ||
564 | case QIC_TAPE_307FT: | ||
565 | /* 307.5 ft 550 Oe Extended Length (XL) tape */ | ||
566 | *tape_len = 307; | ||
567 | break; | ||
568 | case QIC_TAPE_VARIABLE: | ||
569 | /* Variable length 550 Oe tape */ | ||
570 | *tape_len = 0; | ||
571 | break; | ||
572 | case QIC_TAPE_1100FT: | ||
573 | /* 1100 ft 550 Oe tape */ | ||
574 | *tape_len = 1100; | ||
575 | break; | ||
576 | case QIC_TAPE_FLEX: | ||
577 | /* Variable length 900 Oe tape */ | ||
578 | *tape_len = 0; | ||
579 | break; | ||
580 | default: | ||
581 | *tape_len = -1; | ||
582 | break; | ||
583 | } | ||
584 | if (*qic_std == -1 || *tape_len == -1) { | ||
585 | TRACE(ft_t_any, | ||
586 | "post qic-117b spec drive with unknown tape"); | ||
587 | } | ||
588 | result = *tape_len == -1 ? -EIO : 0; | ||
589 | if (status & QIC_TAPE_WIDE) { | ||
590 | switch (*qic_std) { | ||
591 | case QIC_TAPE_QIC80: | ||
592 | TRACE(ft_t_info, "TR-1 tape detected"); | ||
593 | break; | ||
594 | case QIC_TAPE_QIC3010: | ||
595 | TRACE(ft_t_info, "TR-2 tape detected"); | ||
596 | break; | ||
597 | case QIC_TAPE_QIC3020: | ||
598 | TRACE(ft_t_info, "TR-3 tape detected"); | ||
599 | break; | ||
600 | default: | ||
601 | TRACE(ft_t_warn, | ||
602 | "Unknown Travan tape type detected"); | ||
603 | break; | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | TRACE_EXIT (result < 0) ? -EIO : 0; | ||
608 | } | ||
609 | |||
610 | static int ftape_report_rom_version(int *version) | ||
611 | { | ||
612 | |||
613 | if (ftape_report_operation(version, QIC_REPORT_ROM_VERSION, 8) < 0) { | ||
614 | return -EIO; | ||
615 | } else { | ||
616 | return 0; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | void ftape_report_vendor_id(unsigned int *id) | ||
621 | { | ||
622 | int result; | ||
623 | TRACE_FUN(ft_t_any); | ||
624 | |||
625 | /* We'll try to get a vendor id from the drive. First | ||
626 | * according to the QIC-117 spec, a 16-bit id is requested. | ||
627 | * If that fails we'll try an 8-bit version, otherwise we'll | ||
628 | * try an undocumented query. | ||
629 | */ | ||
630 | result = ftape_report_operation((int *) id, QIC_REPORT_VENDOR_ID, 16); | ||
631 | if (result < 0) { | ||
632 | result = ftape_report_operation((int *) id, | ||
633 | QIC_REPORT_VENDOR_ID, 8); | ||
634 | if (result < 0) { | ||
635 | /* The following is an undocumented call found | ||
636 | * in the CMS code. | ||
637 | */ | ||
638 | result = ftape_report_operation((int *) id, 24, 8); | ||
639 | if (result < 0) { | ||
640 | *id = UNKNOWN_VENDOR; | ||
641 | } else { | ||
642 | TRACE(ft_t_noise, "got old 8 bit id: %04x", | ||
643 | *id); | ||
644 | *id |= 0x20000; | ||
645 | } | ||
646 | } else { | ||
647 | TRACE(ft_t_noise, "got 8 bit id: %04x", *id); | ||
648 | *id |= 0x10000; | ||
649 | } | ||
650 | } else { | ||
651 | TRACE(ft_t_noise, "got 16 bit id: %04x", *id); | ||
652 | } | ||
653 | if (*id == 0x0047) { | ||
654 | int version; | ||
655 | int sign; | ||
656 | |||
657 | if (ftape_report_rom_version(&version) < 0) { | ||
658 | TRACE(ft_t_bug, "report rom version failed"); | ||
659 | TRACE_EXIT; | ||
660 | } | ||
661 | TRACE(ft_t_noise, "CMS rom version: %d", version); | ||
662 | ftape_command(QIC_ENTER_DIAGNOSTIC_1); | ||
663 | ftape_command(QIC_ENTER_DIAGNOSTIC_1); | ||
664 | diagnostic_mode = 1; | ||
665 | if (ftape_report_operation(&sign, 9, 8) < 0) { | ||
666 | unsigned int error; | ||
667 | qic117_cmd_t command; | ||
668 | |||
669 | ftape_report_error(&error, &command, 1); | ||
670 | ftape_command(QIC_ENTER_PRIMARY_MODE); | ||
671 | diagnostic_mode = 0; | ||
672 | TRACE_EXIT; /* failure ! */ | ||
673 | } else { | ||
674 | TRACE(ft_t_noise, "CMS signature: %02x", sign); | ||
675 | } | ||
676 | if (sign == 0xa5) { | ||
677 | result = ftape_report_operation(&sign, 37, 8); | ||
678 | if (result < 0) { | ||
679 | if (version >= 63) { | ||
680 | *id = 0x8880; | ||
681 | TRACE(ft_t_noise, | ||
682 | "This is an Iomega drive !"); | ||
683 | } else { | ||
684 | *id = 0x0047; | ||
685 | TRACE(ft_t_noise, | ||
686 | "This is a real CMS drive !"); | ||
687 | } | ||
688 | } else { | ||
689 | *id = 0x0047; | ||
690 | TRACE(ft_t_noise, "CMS status: %d", sign); | ||
691 | } | ||
692 | } else { | ||
693 | *id = UNKNOWN_VENDOR; | ||
694 | } | ||
695 | ftape_command(QIC_ENTER_PRIMARY_MODE); | ||
696 | diagnostic_mode = 0; | ||
697 | } | ||
698 | TRACE_EXIT; | ||
699 | } | ||
700 | |||
701 | static int qic_rate_code(unsigned int rate) | ||
702 | { | ||
703 | switch (rate) { | ||
704 | case 250: | ||
705 | return QIC_CONFIG_RATE_250; | ||
706 | case 500: | ||
707 | return QIC_CONFIG_RATE_500; | ||
708 | case 1000: | ||
709 | return QIC_CONFIG_RATE_1000; | ||
710 | case 2000: | ||
711 | return QIC_CONFIG_RATE_2000; | ||
712 | default: | ||
713 | return QIC_CONFIG_RATE_500; | ||
714 | } | ||
715 | } | ||
716 | |||
717 | static int ftape_set_rate_test(unsigned int *max_rate) | ||
718 | { | ||
719 | unsigned int error; | ||
720 | qic117_cmd_t command; | ||
721 | int status; | ||
722 | int supported = 0; | ||
723 | TRACE_FUN(ft_t_any); | ||
724 | |||
725 | /* Check if the drive does support the select rate command | ||
726 | * by testing all different settings. If any one is accepted | ||
727 | * we assume the command is supported, else not. | ||
728 | */ | ||
729 | for (*max_rate = 2000; *max_rate >= 250; *max_rate /= 2) { | ||
730 | if (ftape_command(QIC_SELECT_RATE) < 0) { | ||
731 | continue; | ||
732 | } | ||
733 | if (ftape_parameter_wait(qic_rate_code(*max_rate), | ||
734 | 1 * FT_SECOND, &status) < 0) { | ||
735 | continue; | ||
736 | } | ||
737 | if (status & QIC_STATUS_ERROR) { | ||
738 | ftape_report_error(&error, &command, 0); | ||
739 | continue; | ||
740 | } | ||
741 | supported = 1; /* did accept a request */ | ||
742 | break; | ||
743 | } | ||
744 | TRACE(ft_t_noise, "Select Rate command is%s supported", | ||
745 | supported ? "" : " not"); | ||
746 | TRACE_EXIT supported; | ||
747 | } | ||
748 | |||
749 | int ftape_set_data_rate(unsigned int new_rate /* Kbps */, unsigned int qic_std) | ||
750 | { | ||
751 | int status; | ||
752 | int result = 0; | ||
753 | unsigned int data_rate = new_rate; | ||
754 | static int supported; | ||
755 | int rate_changed = 0; | ||
756 | qic_model dummy_model; | ||
757 | unsigned int dummy_qic_std, dummy_tape_len; | ||
758 | TRACE_FUN(ft_t_any); | ||
759 | |||
760 | if (ft_drive_max_rate == 0) { /* first time */ | ||
761 | supported = ftape_set_rate_test(&ft_drive_max_rate); | ||
762 | } | ||
763 | if (supported) { | ||
764 | ftape_command(QIC_SELECT_RATE); | ||
765 | result = ftape_parameter_wait(qic_rate_code(new_rate), | ||
766 | 1 * FT_SECOND, &status); | ||
767 | if (result >= 0 && !(status & QIC_STATUS_ERROR)) { | ||
768 | rate_changed = 1; | ||
769 | } | ||
770 | } | ||
771 | TRACE_CATCH(result = ftape_report_configuration(&dummy_model, | ||
772 | &data_rate, | ||
773 | &dummy_qic_std, | ||
774 | &dummy_tape_len),); | ||
775 | if (data_rate != new_rate) { | ||
776 | if (!supported) { | ||
777 | TRACE(ft_t_warn, "Rate change not supported!"); | ||
778 | } else if (rate_changed) { | ||
779 | TRACE(ft_t_warn, "Requested: %d, got %d", | ||
780 | new_rate, data_rate); | ||
781 | } else { | ||
782 | TRACE(ft_t_warn, "Rate change failed!"); | ||
783 | } | ||
784 | result = -EINVAL; | ||
785 | } | ||
786 | /* | ||
787 | * Set data rate and write precompensation as specified: | ||
788 | * | ||
789 | * | QIC-40/80 | QIC-3010/3020 | ||
790 | * rate | precomp | precomp | ||
791 | * ----------+-------------+-------------- | ||
792 | * 250 Kbps. | 250 ns. | 0 ns. | ||
793 | * 500 Kbps. | 125 ns. | 0 ns. | ||
794 | * 1 Mbps. | 42 ns. | 0 ns. | ||
795 | * 2 Mbps | N/A | 0 ns. | ||
796 | */ | ||
797 | if ((qic_std == QIC_TAPE_QIC40 && data_rate > 500) || | ||
798 | (qic_std == QIC_TAPE_QIC80 && data_rate > 1000)) { | ||
799 | TRACE_ABORT(-EINVAL, | ||
800 | ft_t_warn, "Datarate too high for QIC-mode"); | ||
801 | } | ||
802 | TRACE_CATCH(fdc_set_data_rate(data_rate),_res = -EINVAL); | ||
803 | ft_data_rate = data_rate; | ||
804 | if (qic_std == QIC_TAPE_QIC40 || qic_std == QIC_TAPE_QIC80) { | ||
805 | switch (data_rate) { | ||
806 | case 250: | ||
807 | fdc_set_write_precomp(250); | ||
808 | break; | ||
809 | default: | ||
810 | case 500: | ||
811 | fdc_set_write_precomp(125); | ||
812 | break; | ||
813 | case 1000: | ||
814 | fdc_set_write_precomp(42); | ||
815 | break; | ||
816 | } | ||
817 | } else { | ||
818 | fdc_set_write_precomp(0); | ||
819 | } | ||
820 | TRACE_EXIT result; | ||
821 | } | ||
822 | |||
823 | /* The next two functions are used to cope with excessive overrun errors | ||
824 | */ | ||
825 | int ftape_increase_threshold(void) | ||
826 | { | ||
827 | TRACE_FUN(ft_t_flow); | ||
828 | |||
829 | if (fdc.type < i82077 || ft_fdc_threshold >= 12) { | ||
830 | TRACE_ABORT(-EIO, ft_t_err, "cannot increase fifo threshold"); | ||
831 | } | ||
832 | if (fdc_fifo_threshold(++ft_fdc_threshold, NULL, NULL, NULL) < 0) { | ||
833 | TRACE(ft_t_err, "cannot increase fifo threshold"); | ||
834 | ft_fdc_threshold --; | ||
835 | fdc_reset(); | ||
836 | } | ||
837 | TRACE(ft_t_info, "New FIFO threshold: %d", ft_fdc_threshold); | ||
838 | TRACE_EXIT 0; | ||
839 | } | ||
840 | |||
841 | int ftape_half_data_rate(void) | ||
842 | { | ||
843 | if (ft_data_rate < 500) { | ||
844 | return -1; | ||
845 | } | ||
846 | if (ftape_set_data_rate(ft_data_rate / 2, ft_qic_std) < 0) { | ||
847 | return -EIO; | ||
848 | } | ||
849 | ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); | ||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | /* Seek the head to the specified track. | ||
854 | */ | ||
855 | int ftape_seek_head_to_track(unsigned int track) | ||
856 | { | ||
857 | int status; | ||
858 | TRACE_FUN(ft_t_any); | ||
859 | |||
860 | ft_location.track = -1; /* remains set in case of error */ | ||
861 | if (track >= ft_tracks_per_tape) { | ||
862 | TRACE_ABORT(-EINVAL, ft_t_bug, "track out of bounds"); | ||
863 | } | ||
864 | TRACE(ft_t_flow, "seeking track %d", track); | ||
865 | TRACE_CATCH(ftape_command(QIC_SEEK_HEAD_TO_TRACK),); | ||
866 | TRACE_CATCH(ftape_parameter_wait(track, ftape_timeout.head_seek, | ||
867 | &status),); | ||
868 | ft_location.track = track; | ||
869 | ftape_might_be_off_track = 0; | ||
870 | TRACE_EXIT 0; | ||
871 | } | ||
872 | |||
873 | int ftape_wakeup_drive(wake_up_types method) | ||
874 | { | ||
875 | int status; | ||
876 | int motor_on = 0; | ||
877 | TRACE_FUN(ft_t_any); | ||
878 | |||
879 | switch (method) { | ||
880 | case wake_up_colorado: | ||
881 | TRACE_CATCH(ftape_command(QIC_PHANTOM_SELECT),); | ||
882 | TRACE_CATCH(ftape_parameter(0 /* ft_drive_sel ?? */),); | ||
883 | break; | ||
884 | case wake_up_mountain: | ||
885 | TRACE_CATCH(ftape_command(QIC_SOFT_SELECT),); | ||
886 | ftape_sleep(FT_MILLISECOND); /* NEEDED */ | ||
887 | TRACE_CATCH(ftape_parameter(18),); | ||
888 | break; | ||
889 | case wake_up_insight: | ||
890 | ftape_sleep(100 * FT_MILLISECOND); | ||
891 | motor_on = 1; | ||
892 | fdc_motor(motor_on); /* enable is done by motor-on */ | ||
893 | case no_wake_up: | ||
894 | break; | ||
895 | default: | ||
896 | TRACE_EXIT -ENODEV; /* unknown wakeup method */ | ||
897 | break; | ||
898 | } | ||
899 | /* If wakeup succeeded we shouldn't get an error here.. | ||
900 | */ | ||
901 | TRACE_CATCH(ftape_report_raw_drive_status(&status), | ||
902 | if (motor_on) { | ||
903 | fdc_motor(0); | ||
904 | }); | ||
905 | TRACE_EXIT 0; | ||
906 | } | ||
907 | |||
908 | int ftape_put_drive_to_sleep(wake_up_types method) | ||
909 | { | ||
910 | TRACE_FUN(ft_t_any); | ||
911 | |||
912 | switch (method) { | ||
913 | case wake_up_colorado: | ||
914 | TRACE_CATCH(ftape_command(QIC_PHANTOM_DESELECT),); | ||
915 | break; | ||
916 | case wake_up_mountain: | ||
917 | TRACE_CATCH(ftape_command(QIC_SOFT_DESELECT),); | ||
918 | break; | ||
919 | case wake_up_insight: | ||
920 | fdc_motor(0); /* enable is done by motor-on */ | ||
921 | case no_wake_up: /* no wakeup / no sleep ! */ | ||
922 | break; | ||
923 | default: | ||
924 | TRACE_EXIT -ENODEV; /* unknown wakeup method */ | ||
925 | } | ||
926 | TRACE_EXIT 0; | ||
927 | } | ||
928 | |||
929 | int ftape_reset_drive(void) | ||
930 | { | ||
931 | int result = 0; | ||
932 | int status; | ||
933 | unsigned int err_code; | ||
934 | qic117_cmd_t err_command; | ||
935 | int i; | ||
936 | TRACE_FUN(ft_t_any); | ||
937 | |||
938 | /* We want to re-establish contact with our drive. Fire a | ||
939 | * number of reset commands (single step pulses) and pray for | ||
940 | * success. | ||
941 | */ | ||
942 | for (i = 0; i < 2; ++i) { | ||
943 | TRACE(ft_t_flow, "Resetting fdc"); | ||
944 | fdc_reset(); | ||
945 | ftape_sleep(10 * FT_MILLISECOND); | ||
946 | TRACE(ft_t_flow, "Reset command to drive"); | ||
947 | result = ftape_command(QIC_RESET); | ||
948 | if (result == 0) { | ||
949 | ftape_sleep(1 * FT_SECOND); /* drive not | ||
950 | * accessible | ||
951 | * during 1 second | ||
952 | */ | ||
953 | TRACE(ft_t_flow, "Re-selecting drive"); | ||
954 | |||
955 | /* Strange, the QIC-117 specs don't mention | ||
956 | * this but the drive gets deselected after a | ||
957 | * soft reset ! So we need to enable it | ||
958 | * again. | ||
959 | */ | ||
960 | if (ftape_wakeup_drive(ft_drive_type.wake_up) < 0) { | ||
961 | TRACE(ft_t_err, "Wakeup failed !"); | ||
962 | } | ||
963 | TRACE(ft_t_flow, "Waiting until drive gets ready"); | ||
964 | result= ftape_ready_wait(ftape_timeout.reset, &status); | ||
965 | if (result == 0 && (status & QIC_STATUS_ERROR)) { | ||
966 | result = ftape_report_error(&err_code, | ||
967 | &err_command, 1); | ||
968 | if (result == 0 && err_code == 27) { | ||
969 | /* Okay, drive saw reset | ||
970 | * command and responded as it | ||
971 | * should | ||
972 | */ | ||
973 | break; | ||
974 | } else { | ||
975 | result = -EIO; | ||
976 | } | ||
977 | } else { | ||
978 | result = -EIO; | ||
979 | } | ||
980 | } | ||
981 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
982 | } | ||
983 | if (result != 0) { | ||
984 | TRACE(ft_t_err, "General failure to reset tape drive"); | ||
985 | } else { | ||
986 | /* Restore correct settings: keep original rate | ||
987 | */ | ||
988 | ftape_set_data_rate(ft_data_rate, ft_qic_std); | ||
989 | } | ||
990 | ftape_init_drive_needed = 1; | ||
991 | TRACE_EXIT result; | ||
992 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-io.h b/drivers/char/ftape/lowlevel/ftape-io.h deleted file mode 100644 index 26a7baad8717..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-io.h +++ /dev/null | |||
@@ -1,90 +0,0 @@ | |||
1 | #ifndef _FTAPE_IO_H | ||
2 | #define _FTAPE_IO_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-io.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:18 $ | ||
26 | * | ||
27 | * This file contains definitions for the glue part of the | ||
28 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
29 | */ | ||
30 | |||
31 | #include <linux/qic117.h> | ||
32 | #include <linux/ftape-vendors.h> | ||
33 | |||
34 | typedef struct { | ||
35 | unsigned int seek; | ||
36 | unsigned int reset; | ||
37 | unsigned int rewind; | ||
38 | unsigned int head_seek; | ||
39 | unsigned int stop; | ||
40 | unsigned int pause; | ||
41 | } ft_timeout_table; | ||
42 | |||
43 | typedef enum { | ||
44 | prehistoric, pre_qic117c, post_qic117b, post_qic117d | ||
45 | } qic_model; | ||
46 | |||
47 | /* | ||
48 | * ftape-io.c defined global vars. | ||
49 | */ | ||
50 | extern ft_timeout_table ftape_timeout; | ||
51 | extern unsigned int ftape_tape_len; | ||
52 | extern volatile qic117_cmd_t ftape_current_command; | ||
53 | extern const struct qic117_command_table qic117_cmds[]; | ||
54 | extern int ftape_might_be_off_track; | ||
55 | |||
56 | /* | ||
57 | * ftape-io.c defined global functions. | ||
58 | */ | ||
59 | extern void ftape_udelay(unsigned int usecs); | ||
60 | extern void ftape_udelay_calibrate(void); | ||
61 | extern void ftape_sleep(unsigned int time); | ||
62 | extern void ftape_report_vendor_id(unsigned int *id); | ||
63 | extern int ftape_command(qic117_cmd_t command); | ||
64 | extern int ftape_command_wait(qic117_cmd_t command, | ||
65 | unsigned int timeout, | ||
66 | int *status); | ||
67 | extern int ftape_parameter(unsigned int parameter); | ||
68 | extern int ftape_report_operation(int *status, | ||
69 | qic117_cmd_t command, | ||
70 | int result_length); | ||
71 | extern int ftape_report_configuration(qic_model *model, | ||
72 | unsigned int *rate, | ||
73 | int *qic_std, | ||
74 | int *tape_len); | ||
75 | extern int ftape_report_drive_status(int *status); | ||
76 | extern int ftape_report_raw_drive_status(int *status); | ||
77 | extern int ftape_report_status(int *status); | ||
78 | extern int ftape_ready_wait(unsigned int timeout, int *status); | ||
79 | extern int ftape_seek_head_to_track(unsigned int track); | ||
80 | extern int ftape_set_data_rate(unsigned int new_rate, unsigned int qic_std); | ||
81 | extern int ftape_report_error(unsigned int *error, | ||
82 | qic117_cmd_t *command, | ||
83 | int report); | ||
84 | extern int ftape_reset_drive(void); | ||
85 | extern int ftape_put_drive_to_sleep(wake_up_types method); | ||
86 | extern int ftape_wakeup_drive(wake_up_types method); | ||
87 | extern int ftape_increase_threshold(void); | ||
88 | extern int ftape_half_data_rate(void); | ||
89 | |||
90 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-proc.c b/drivers/char/ftape/lowlevel/ftape-proc.c deleted file mode 100644 index e805b15e0a12..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-proc.c +++ /dev/null | |||
@@ -1,214 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1997 Claus-Justus Heine | ||
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 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-proc.c,v $ | ||
20 | * $Revision: 1.11 $ | ||
21 | * $Date: 1997/10/24 14:47:37 $ | ||
22 | * | ||
23 | * This file contains the procfs interface for the | ||
24 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
25 | |||
26 | * Old code removed, switched to dynamic proc entry. | ||
27 | */ | ||
28 | |||
29 | |||
30 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) | ||
31 | |||
32 | #include <linux/proc_fs.h> | ||
33 | |||
34 | #include <linux/ftape.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/qic117.h> | ||
37 | |||
38 | #include "../lowlevel/ftape-io.h" | ||
39 | #include "../lowlevel/ftape-ctl.h" | ||
40 | #include "../lowlevel/ftape-proc.h" | ||
41 | #include "../lowlevel/ftape-tracing.h" | ||
42 | |||
43 | static size_t get_driver_info(char *buf) | ||
44 | { | ||
45 | const char *debug_level[] = { "bugs" , | ||
46 | "errors", | ||
47 | "warnings", | ||
48 | "informational", | ||
49 | "noisy", | ||
50 | "program flow", | ||
51 | "fdc and dma", | ||
52 | "data flow", | ||
53 | "anything" }; | ||
54 | |||
55 | return sprintf(buf, | ||
56 | "version : %s\n" | ||
57 | "used data rate: %d kbit/sec\n" | ||
58 | "dma memory : %d kb\n" | ||
59 | "debug messages: %s\n", | ||
60 | FTAPE_VERSION, | ||
61 | ft_data_rate, | ||
62 | FT_BUFF_SIZE * ft_nr_buffers >> 10, | ||
63 | debug_level[TRACE_LEVEL]); | ||
64 | } | ||
65 | |||
66 | static size_t get_tapedrive_info(char *buf) | ||
67 | { | ||
68 | return sprintf(buf, | ||
69 | "vendor id : 0x%04x\n" | ||
70 | "drive name: %s\n" | ||
71 | "wind speed: %d ips\n" | ||
72 | "wakeup : %s\n" | ||
73 | "max. rate : %d kbit/sec\n", | ||
74 | ft_drive_type.vendor_id, | ||
75 | ft_drive_type.name, | ||
76 | ft_drive_type.speed, | ||
77 | ((ft_drive_type.wake_up == no_wake_up) | ||
78 | ? "No wakeup needed" : | ||
79 | ((ft_drive_type.wake_up == wake_up_colorado) | ||
80 | ? "Colorado" : | ||
81 | ((ft_drive_type.wake_up == wake_up_mountain) | ||
82 | ? "Mountain" : | ||
83 | ((ft_drive_type.wake_up == wake_up_insight) | ||
84 | ? "Motor on" : | ||
85 | "Unknown")))), | ||
86 | ft_drive_max_rate); | ||
87 | } | ||
88 | |||
89 | static size_t get_cartridge_info(char *buf) | ||
90 | { | ||
91 | if (ftape_init_drive_needed) { | ||
92 | return sprintf(buf, "uninitialized\n"); | ||
93 | } | ||
94 | if (ft_no_tape) { | ||
95 | return sprintf(buf, "no cartridge inserted\n"); | ||
96 | } | ||
97 | return sprintf(buf, | ||
98 | "segments : %5d\n" | ||
99 | "tracks : %5d\n" | ||
100 | "length : %5dft\n" | ||
101 | "formatted : %3s\n" | ||
102 | "writable : %3s\n" | ||
103 | "QIC spec. : QIC-%s\n" | ||
104 | "fmt-code : %1d\n", | ||
105 | ft_segments_per_track, | ||
106 | ft_tracks_per_tape, | ||
107 | ftape_tape_len, | ||
108 | (ft_formatted == 1) ? "yes" : "no", | ||
109 | (ft_write_protected == 1) ? "no" : "yes", | ||
110 | ((ft_qic_std == QIC_TAPE_QIC40) ? "40" : | ||
111 | ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : | ||
112 | ((ft_qic_std == QIC_TAPE_QIC3010) ? "3010" : | ||
113 | ((ft_qic_std == QIC_TAPE_QIC3020) ? "3020" : | ||
114 | "???")))), | ||
115 | ft_format_code); | ||
116 | } | ||
117 | |||
118 | static size_t get_controller_info(char *buf) | ||
119 | { | ||
120 | const char *fdc_name[] = { "no fdc", | ||
121 | "i8272", | ||
122 | "i82077", | ||
123 | "i82077AA", | ||
124 | "Colorado FC-10 or FC-20", | ||
125 | "i82078", | ||
126 | "i82078_1" }; | ||
127 | |||
128 | return sprintf(buf, | ||
129 | "FDC type : %s\n" | ||
130 | "FDC base : 0x%03x\n" | ||
131 | "FDC irq : %d\n" | ||
132 | "FDC dma : %d\n" | ||
133 | "FDC thr. : %d\n" | ||
134 | "max. rate : %d kbit/sec\n", | ||
135 | ft_mach2 ? "Mountain MACH-2" : fdc_name[fdc.type], | ||
136 | fdc.sra, fdc.irq, fdc.dma, | ||
137 | ft_fdc_threshold, ft_fdc_max_rate); | ||
138 | } | ||
139 | |||
140 | static size_t get_history_info(char *buf) | ||
141 | { | ||
142 | size_t len; | ||
143 | |||
144 | len = sprintf(buf, | ||
145 | "\nFDC isr statistics\n" | ||
146 | " id_am_errors : %3d\n" | ||
147 | " id_crc_errors : %3d\n" | ||
148 | " data_am_errors : %3d\n" | ||
149 | " data_crc_errors : %3d\n" | ||
150 | " overrun_errors : %3d\n" | ||
151 | " no_data_errors : %3d\n" | ||
152 | " retries : %3d\n", | ||
153 | ft_history.id_am_errors, ft_history.id_crc_errors, | ||
154 | ft_history.data_am_errors, ft_history.data_crc_errors, | ||
155 | ft_history.overrun_errors, ft_history.no_data_errors, | ||
156 | ft_history.retries); | ||
157 | len += sprintf(buf + len, | ||
158 | "\nECC statistics\n" | ||
159 | " crc_errors : %3d\n" | ||
160 | " crc_failures : %3d\n" | ||
161 | " ecc_failures : %3d\n" | ||
162 | " sectors corrected: %3d\n", | ||
163 | ft_history.crc_errors, ft_history.crc_failures, | ||
164 | ft_history.ecc_failures, ft_history.corrected); | ||
165 | len += sprintf(buf + len, | ||
166 | "\ntape quality statistics\n" | ||
167 | " media defects : %3d\n", | ||
168 | ft_history.defects); | ||
169 | len += sprintf(buf + len, | ||
170 | "\ntape motion statistics\n" | ||
171 | " repositions : %3d\n", | ||
172 | ft_history.rewinds); | ||
173 | return len; | ||
174 | } | ||
175 | |||
176 | static int ftape_read_proc(char *page, char **start, off_t off, | ||
177 | int count, int *eof, void *data) | ||
178 | { | ||
179 | char *ptr = page; | ||
180 | size_t len; | ||
181 | |||
182 | ptr += sprintf(ptr, "Kernel Driver\n\n"); | ||
183 | ptr += get_driver_info(ptr); | ||
184 | ptr += sprintf(ptr, "\nTape Drive\n\n"); | ||
185 | ptr += get_tapedrive_info(ptr); | ||
186 | ptr += sprintf(ptr, "\nFDC Controller\n\n"); | ||
187 | ptr += get_controller_info(ptr); | ||
188 | ptr += sprintf(ptr, "\nTape Cartridge\n\n"); | ||
189 | ptr += get_cartridge_info(ptr); | ||
190 | ptr += sprintf(ptr, "\nHistory Record\n\n"); | ||
191 | ptr += get_history_info(ptr); | ||
192 | |||
193 | len = strlen(page); | ||
194 | *start = NULL; | ||
195 | if (off+count >= len) { | ||
196 | *eof = 1; | ||
197 | } else { | ||
198 | *eof = 0; | ||
199 | } | ||
200 | return len; | ||
201 | } | ||
202 | |||
203 | int __init ftape_proc_init(void) | ||
204 | { | ||
205 | return create_proc_read_entry("ftape", 0, &proc_root, | ||
206 | ftape_read_proc, NULL) != NULL; | ||
207 | } | ||
208 | |||
209 | void ftape_proc_destroy(void) | ||
210 | { | ||
211 | remove_proc_entry("ftape", &proc_root); | ||
212 | } | ||
213 | |||
214 | #endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-proc.h b/drivers/char/ftape/lowlevel/ftape-proc.h deleted file mode 100644 index 264dfcc1d22d..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-proc.h +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | #ifndef _FTAPE_PROC_H | ||
2 | #define _FTAPE_PROC_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1997 Claus-Justus Heine | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-proc.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:18:20 $ | ||
25 | * | ||
26 | * This file contains definitions for the procfs interface of the | ||
27 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
28 | */ | ||
29 | |||
30 | #include <linux/proc_fs.h> | ||
31 | |||
32 | extern int ftape_proc_init(void); | ||
33 | extern void ftape_proc_destroy(void); | ||
34 | |||
35 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-read.c b/drivers/char/ftape/lowlevel/ftape-read.c deleted file mode 100644 index d967d8cd86dc..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-read.c +++ /dev/null | |||
@@ -1,621 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-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: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-read.c,v $ | ||
21 | * $Revision: 1.6 $ | ||
22 | * $Date: 1997/10/21 14:39:22 $ | ||
23 | * | ||
24 | * This file contains the reading code | ||
25 | * for the QIC-117 floppy-tape driver for Linux. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <linux/string.h> | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/mm.h> | ||
32 | |||
33 | #include <linux/ftape.h> | ||
34 | #include <linux/qic117.h> | ||
35 | #include "../lowlevel/ftape-tracing.h" | ||
36 | #include "../lowlevel/ftape-read.h" | ||
37 | #include "../lowlevel/ftape-io.h" | ||
38 | #include "../lowlevel/ftape-ctl.h" | ||
39 | #include "../lowlevel/ftape-rw.h" | ||
40 | #include "../lowlevel/ftape-write.h" | ||
41 | #include "../lowlevel/ftape-ecc.h" | ||
42 | #include "../lowlevel/ftape-bsm.h" | ||
43 | |||
44 | /* Global vars. | ||
45 | */ | ||
46 | |||
47 | /* Local vars. | ||
48 | */ | ||
49 | |||
50 | void ftape_zap_read_buffers(void) | ||
51 | { | ||
52 | int i; | ||
53 | |||
54 | for (i = 0; i < ft_nr_buffers; ++i) { | ||
55 | /* changed to "fit" with dynamic allocation of tape_buffer. --khp */ | ||
56 | ft_buffer[i]->status = waiting; | ||
57 | ft_buffer[i]->bytes = 0; | ||
58 | ft_buffer[i]->skip = 0; | ||
59 | ft_buffer[i]->retry = 0; | ||
60 | } | ||
61 | /* ftape_reset_buffer(); */ | ||
62 | } | ||
63 | |||
64 | static SectorMap convert_sector_map(buffer_struct * buff) | ||
65 | { | ||
66 | int i = 0; | ||
67 | SectorMap bad_map = ftape_get_bad_sector_entry(buff->segment_id); | ||
68 | SectorMap src_map = buff->soft_error_map | buff->hard_error_map; | ||
69 | SectorMap dst_map = 0; | ||
70 | TRACE_FUN(ft_t_any); | ||
71 | |||
72 | if (bad_map || src_map) { | ||
73 | TRACE(ft_t_flow, "bad_map = 0x%08lx", (long) bad_map); | ||
74 | TRACE(ft_t_flow, "src_map = 0x%08lx", (long) src_map); | ||
75 | } | ||
76 | while (bad_map) { | ||
77 | while ((bad_map & 1) == 0) { | ||
78 | if (src_map & 1) { | ||
79 | dst_map |= (1 << i); | ||
80 | } | ||
81 | src_map >>= 1; | ||
82 | bad_map >>= 1; | ||
83 | ++i; | ||
84 | } | ||
85 | /* (bad_map & 1) == 1 */ | ||
86 | src_map >>= 1; | ||
87 | bad_map >>= 1; | ||
88 | } | ||
89 | if (src_map) { | ||
90 | dst_map |= (src_map << i); | ||
91 | } | ||
92 | if (dst_map) { | ||
93 | TRACE(ft_t_flow, "dst_map = 0x%08lx", (long) dst_map); | ||
94 | } | ||
95 | TRACE_EXIT dst_map; | ||
96 | } | ||
97 | |||
98 | static int correct_and_copy_fraction(buffer_struct *buff, __u8 * destination, | ||
99 | int start, int size) | ||
100 | { | ||
101 | struct memory_segment mseg; | ||
102 | int result; | ||
103 | SectorMap read_bad; | ||
104 | TRACE_FUN(ft_t_any); | ||
105 | |||
106 | mseg.read_bad = convert_sector_map(buff); | ||
107 | mseg.marked_bad = 0; /* not used... */ | ||
108 | mseg.blocks = buff->bytes / FT_SECTOR_SIZE; | ||
109 | mseg.data = buff->address; | ||
110 | /* If there are no data sectors we can skip this segment. | ||
111 | */ | ||
112 | if (mseg.blocks <= 3) { | ||
113 | TRACE_ABORT(0, ft_t_noise, "empty segment"); | ||
114 | } | ||
115 | read_bad = mseg.read_bad; | ||
116 | ft_history.crc_errors += count_ones(read_bad); | ||
117 | result = ftape_ecc_correct_data(&mseg); | ||
118 | if (read_bad != 0 || mseg.corrected != 0) { | ||
119 | TRACE(ft_t_noise, "crc error map: 0x%08lx", (unsigned long)read_bad); | ||
120 | TRACE(ft_t_noise, "corrected map: 0x%08lx", (unsigned long)mseg.corrected); | ||
121 | ft_history.corrected += count_ones(mseg.corrected); | ||
122 | } | ||
123 | if (result == ECC_CORRECTED || result == ECC_OK) { | ||
124 | if (result == ECC_CORRECTED) { | ||
125 | TRACE(ft_t_info, "ecc corrected segment: %d", buff->segment_id); | ||
126 | } | ||
127 | if(start < 0) { | ||
128 | start= 0; | ||
129 | } | ||
130 | if((start+size) > ((mseg.blocks - 3) * FT_SECTOR_SIZE)) { | ||
131 | size = (mseg.blocks - 3) * FT_SECTOR_SIZE - start; | ||
132 | } | ||
133 | if (size < 0) { | ||
134 | size= 0; | ||
135 | } | ||
136 | if(size > 0) { | ||
137 | memcpy(destination + start, mseg.data + start, size); | ||
138 | } | ||
139 | if ((read_bad ^ mseg.corrected) & mseg.corrected) { | ||
140 | /* sectors corrected without crc errors set */ | ||
141 | ft_history.crc_failures++; | ||
142 | } | ||
143 | TRACE_EXIT size; /* (mseg.blocks - 3) * FT_SECTOR_SIZE; */ | ||
144 | } else { | ||
145 | ft_history.ecc_failures++; | ||
146 | TRACE_ABORT(-EAGAIN, | ||
147 | ft_t_err, "ecc failure on segment %d", | ||
148 | buff->segment_id); | ||
149 | } | ||
150 | TRACE_EXIT 0; | ||
151 | } | ||
152 | |||
153 | /* Read given segment into buffer at address. | ||
154 | */ | ||
155 | int ftape_read_segment_fraction(const int segment_id, | ||
156 | void *address, | ||
157 | const ft_read_mode_t read_mode, | ||
158 | const int start, | ||
159 | const int size) | ||
160 | { | ||
161 | int result = 0; | ||
162 | int retry = 0; | ||
163 | int bytes_read = 0; | ||
164 | int read_done = 0; | ||
165 | TRACE_FUN(ft_t_flow); | ||
166 | |||
167 | ft_history.used |= 1; | ||
168 | TRACE(ft_t_data_flow, "segment_id = %d", segment_id); | ||
169 | if (ft_driver_state != reading) { | ||
170 | TRACE(ft_t_noise, "calling ftape_abort_operation"); | ||
171 | TRACE_CATCH(ftape_abort_operation(),); | ||
172 | ftape_set_state(reading); | ||
173 | } | ||
174 | for(;;) { | ||
175 | buffer_struct *tail; | ||
176 | /* Allow escape from this loop on signal ! | ||
177 | */ | ||
178 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
179 | /* Search all full buffers for the first matching the | ||
180 | * wanted segment. Clear other buffers on the fly. | ||
181 | */ | ||
182 | tail = ftape_get_buffer(ft_queue_tail); | ||
183 | while (!read_done && tail->status == done) { | ||
184 | /* Allow escape from this loop on signal ! | ||
185 | */ | ||
186 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
187 | if (tail->segment_id == segment_id) { | ||
188 | /* If out buffer is already full, | ||
189 | * return its contents. | ||
190 | */ | ||
191 | TRACE(ft_t_flow, "found segment in cache: %d", | ||
192 | segment_id); | ||
193 | if (tail->deleted) { | ||
194 | /* Return a value that | ||
195 | * read_header_segment | ||
196 | * understands. As this | ||
197 | * should only occur when | ||
198 | * searching for the header | ||
199 | * segments it shouldn't be | ||
200 | * misinterpreted elsewhere. | ||
201 | */ | ||
202 | TRACE_EXIT 0; | ||
203 | } | ||
204 | result = correct_and_copy_fraction( | ||
205 | tail, | ||
206 | address, | ||
207 | start, | ||
208 | size); | ||
209 | TRACE(ft_t_flow, "segment contains (bytes): %d", | ||
210 | result); | ||
211 | if (result < 0) { | ||
212 | if (result != -EAGAIN) { | ||
213 | TRACE_EXIT result; | ||
214 | } | ||
215 | /* keep read_done == 0, will | ||
216 | * trigger | ||
217 | * ftape_abort_operation | ||
218 | * because reading wrong | ||
219 | * segment. | ||
220 | */ | ||
221 | TRACE(ft_t_err, "ecc failed, retry"); | ||
222 | ++retry; | ||
223 | } else { | ||
224 | read_done = 1; | ||
225 | bytes_read = result; | ||
226 | } | ||
227 | } else { | ||
228 | TRACE(ft_t_flow,"zapping segment in cache: %d", | ||
229 | tail->segment_id); | ||
230 | } | ||
231 | tail->status = waiting; | ||
232 | tail = ftape_next_buffer(ft_queue_tail); | ||
233 | } | ||
234 | if (!read_done && tail->status == reading) { | ||
235 | if (tail->segment_id == segment_id) { | ||
236 | switch(ftape_wait_segment(reading)) { | ||
237 | case 0: | ||
238 | break; | ||
239 | case -EINTR: | ||
240 | TRACE_ABORT(-EINTR, ft_t_warn, | ||
241 | "interrupted by " | ||
242 | "non-blockable signal"); | ||
243 | break; | ||
244 | default: | ||
245 | TRACE(ft_t_noise, | ||
246 | "wait_segment failed"); | ||
247 | ftape_abort_operation(); | ||
248 | ftape_set_state(reading); | ||
249 | break; | ||
250 | } | ||
251 | } else { | ||
252 | /* We're reading the wrong segment, | ||
253 | * stop runner. | ||
254 | */ | ||
255 | TRACE(ft_t_noise, "reading wrong segment"); | ||
256 | ftape_abort_operation(); | ||
257 | ftape_set_state(reading); | ||
258 | } | ||
259 | } | ||
260 | /* should runner stop ? | ||
261 | */ | ||
262 | if (ft_runner_status == aborting) { | ||
263 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
264 | switch(head->status) { | ||
265 | case error: | ||
266 | ft_history.defects += | ||
267 | count_ones(head->hard_error_map); | ||
268 | case reading: | ||
269 | head->status = waiting; | ||
270 | break; | ||
271 | default: | ||
272 | break; | ||
273 | } | ||
274 | TRACE_CATCH(ftape_dumb_stop(),); | ||
275 | } else { | ||
276 | /* If just passed last segment on tape: wait | ||
277 | * for BOT or EOT mark. Sets ft_runner_status to | ||
278 | * idle if at lEOT and successful | ||
279 | */ | ||
280 | TRACE_CATCH(ftape_handle_logical_eot(),); | ||
281 | } | ||
282 | /* If we got a segment: quit, or else retry up to limit. | ||
283 | * | ||
284 | * If segment to read is empty, do not start runner for it, | ||
285 | * but wait for next read call. | ||
286 | */ | ||
287 | if (read_done || | ||
288 | ftape_get_bad_sector_entry(segment_id) == EMPTY_SEGMENT ) { | ||
289 | /* bytes_read = 0; should still be zero */ | ||
290 | TRACE_EXIT bytes_read; | ||
291 | |||
292 | } | ||
293 | if (retry > FT_RETRIES_ON_ECC_ERROR) { | ||
294 | ft_history.defects++; | ||
295 | TRACE_ABORT(-ENODATA, ft_t_err, | ||
296 | "too many retries on ecc failure"); | ||
297 | } | ||
298 | /* Now at least one buffer is empty ! | ||
299 | * Restart runner & tape if needed. | ||
300 | */ | ||
301 | TRACE(ft_t_any, "head: %d, tail: %d, ft_runner_status: %d", | ||
302 | ftape_buffer_id(ft_queue_head), | ||
303 | ftape_buffer_id(ft_queue_tail), | ||
304 | ft_runner_status); | ||
305 | TRACE(ft_t_any, "buffer[].status, [head]: %d, [tail]: %d", | ||
306 | ftape_get_buffer(ft_queue_head)->status, | ||
307 | ftape_get_buffer(ft_queue_tail)->status); | ||
308 | tail = ftape_get_buffer(ft_queue_tail); | ||
309 | if (tail->status == waiting) { | ||
310 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
311 | |||
312 | ftape_setup_new_segment(head, segment_id, -1); | ||
313 | if (read_mode == FT_RD_SINGLE) { | ||
314 | /* disable read-ahead */ | ||
315 | head->next_segment = 0; | ||
316 | } | ||
317 | ftape_calc_next_cluster(head); | ||
318 | if (ft_runner_status == idle) { | ||
319 | result = ftape_start_tape(segment_id, | ||
320 | head->sector_offset); | ||
321 | if (result < 0) { | ||
322 | TRACE_ABORT(result, ft_t_err, "Error: " | ||
323 | "segment %d unreachable", | ||
324 | segment_id); | ||
325 | } | ||
326 | } | ||
327 | head->status = reading; | ||
328 | fdc_setup_read_write(head, FDC_READ); | ||
329 | } | ||
330 | } | ||
331 | /* not reached */ | ||
332 | TRACE_EXIT -EIO; | ||
333 | } | ||
334 | |||
335 | int ftape_read_header_segment(__u8 *address) | ||
336 | { | ||
337 | int result; | ||
338 | int header_segment; | ||
339 | int first_failed = 0; | ||
340 | int status; | ||
341 | TRACE_FUN(ft_t_flow); | ||
342 | |||
343 | ft_used_header_segment = -1; | ||
344 | TRACE_CATCH(ftape_report_drive_status(&status),); | ||
345 | TRACE(ft_t_flow, "reading..."); | ||
346 | /* We're looking for the first header segment. | ||
347 | * A header segment cannot contain bad sectors, therefor at the | ||
348 | * tape start, segments with bad sectors are (according to QIC-40/80) | ||
349 | * written with deleted data marks and must be skipped. | ||
350 | */ | ||
351 | memset(address, '\0', (FT_SECTORS_PER_SEGMENT - 3) * FT_SECTOR_SIZE); | ||
352 | result = 0; | ||
353 | #define HEADER_SEGMENT_BOUNDARY 68 /* why not 42? */ | ||
354 | for (header_segment = 0; | ||
355 | header_segment < HEADER_SEGMENT_BOUNDARY && result == 0; | ||
356 | ++header_segment) { | ||
357 | /* Set no read-ahead, the isr will force read-ahead whenever | ||
358 | * it encounters deleted data ! | ||
359 | */ | ||
360 | result = ftape_read_segment(header_segment, | ||
361 | address, | ||
362 | FT_RD_SINGLE); | ||
363 | if (result < 0 && !first_failed) { | ||
364 | TRACE(ft_t_err, "header segment damaged, trying backup"); | ||
365 | first_failed = 1; | ||
366 | result = 0; /* force read of next (backup) segment */ | ||
367 | } | ||
368 | } | ||
369 | if (result < 0 || header_segment >= HEADER_SEGMENT_BOUNDARY) { | ||
370 | TRACE_ABORT(-EIO, ft_t_err, | ||
371 | "no readable header segment found"); | ||
372 | } | ||
373 | TRACE_CATCH(ftape_abort_operation(),); | ||
374 | ft_used_header_segment = header_segment; | ||
375 | result = ftape_decode_header_segment(address); | ||
376 | TRACE_EXIT result; | ||
377 | } | ||
378 | |||
379 | int ftape_decode_header_segment(__u8 *address) | ||
380 | { | ||
381 | unsigned int max_floppy_side; | ||
382 | unsigned int max_floppy_track; | ||
383 | unsigned int max_floppy_sector; | ||
384 | unsigned int new_tape_len; | ||
385 | TRACE_FUN(ft_t_flow); | ||
386 | |||
387 | if (GET4(address, FT_SIGNATURE) == FT_D2G_MAGIC) { | ||
388 | /* Ditto 2GB header segment. They encrypt the bad sector map. | ||
389 | * We decrypt it and store them in normal format. | ||
390 | * I hope this is correct. | ||
391 | */ | ||
392 | int i; | ||
393 | TRACE(ft_t_warn, | ||
394 | "Found Ditto 2GB tape, " | ||
395 | "trying to decrypt bad sector map"); | ||
396 | for (i=256; i < 29 * FT_SECTOR_SIZE; i++) { | ||
397 | address[i] = ~(address[i] - (i&0xff)); | ||
398 | } | ||
399 | PUT4(address, 0,FT_HSEG_MAGIC); | ||
400 | } else if (GET4(address, FT_SIGNATURE) != FT_HSEG_MAGIC) { | ||
401 | TRACE_ABORT(-EIO, ft_t_err, | ||
402 | "wrong signature in header segment"); | ||
403 | } | ||
404 | ft_format_code = (ft_format_type) address[FT_FMT_CODE]; | ||
405 | if (ft_format_code != fmt_big) { | ||
406 | ft_header_segment_1 = GET2(address, FT_HSEG_1); | ||
407 | ft_header_segment_2 = GET2(address, FT_HSEG_2); | ||
408 | ft_first_data_segment = GET2(address, FT_FRST_SEG); | ||
409 | ft_last_data_segment = GET2(address, FT_LAST_SEG); | ||
410 | } else { | ||
411 | ft_header_segment_1 = GET4(address, FT_6_HSEG_1); | ||
412 | ft_header_segment_2 = GET4(address, FT_6_HSEG_2); | ||
413 | ft_first_data_segment = GET4(address, FT_6_FRST_SEG); | ||
414 | ft_last_data_segment = GET4(address, FT_6_LAST_SEG); | ||
415 | } | ||
416 | TRACE(ft_t_noise, "first data segment: %d", ft_first_data_segment); | ||
417 | TRACE(ft_t_noise, "last data segment: %d", ft_last_data_segment); | ||
418 | TRACE(ft_t_noise, "header segments are %d and %d", | ||
419 | ft_header_segment_1, ft_header_segment_2); | ||
420 | |||
421 | /* Verify tape parameters... | ||
422 | * QIC-40/80 spec: tape_parameters: | ||
423 | * | ||
424 | * segments-per-track segments_per_track | ||
425 | * tracks-per-cartridge tracks_per_tape | ||
426 | * max-floppy-side (segments_per_track * | ||
427 | * tracks_per_tape - 1) / | ||
428 | * ftape_segments_per_head | ||
429 | * max-floppy-track ftape_segments_per_head / | ||
430 | * ftape_segments_per_cylinder - 1 | ||
431 | * max-floppy-sector ftape_segments_per_cylinder * | ||
432 | * FT_SECTORS_PER_SEGMENT | ||
433 | */ | ||
434 | ft_segments_per_track = GET2(address, FT_SPT); | ||
435 | ft_tracks_per_tape = address[FT_TPC]; | ||
436 | max_floppy_side = address[FT_FHM]; | ||
437 | max_floppy_track = address[FT_FTM]; | ||
438 | max_floppy_sector = address[FT_FSM]; | ||
439 | TRACE(ft_t_noise, "(fmt/spt/tpc/fhm/ftm/fsm) = %d/%d/%d/%d/%d/%d", | ||
440 | ft_format_code, ft_segments_per_track, ft_tracks_per_tape, | ||
441 | max_floppy_side, max_floppy_track, max_floppy_sector); | ||
442 | new_tape_len = ftape_tape_len; | ||
443 | switch (ft_format_code) { | ||
444 | case fmt_425ft: | ||
445 | new_tape_len = 425; | ||
446 | break; | ||
447 | case fmt_normal: | ||
448 | if (ftape_tape_len == 0) { /* otherwise 307 ft */ | ||
449 | new_tape_len = 205; | ||
450 | } | ||
451 | break; | ||
452 | case fmt_1100ft: | ||
453 | new_tape_len = 1100; | ||
454 | break; | ||
455 | case fmt_var:{ | ||
456 | int segments_per_1000_inch = 1; /* non-zero default for switch */ | ||
457 | switch (ft_qic_std) { | ||
458 | case QIC_TAPE_QIC40: | ||
459 | segments_per_1000_inch = 332; | ||
460 | break; | ||
461 | case QIC_TAPE_QIC80: | ||
462 | segments_per_1000_inch = 488; | ||
463 | break; | ||
464 | case QIC_TAPE_QIC3010: | ||
465 | segments_per_1000_inch = 730; | ||
466 | break; | ||
467 | case QIC_TAPE_QIC3020: | ||
468 | segments_per_1000_inch = 1430; | ||
469 | break; | ||
470 | } | ||
471 | new_tape_len = (1000 * ft_segments_per_track + | ||
472 | (segments_per_1000_inch - 1)) / segments_per_1000_inch; | ||
473 | break; | ||
474 | } | ||
475 | case fmt_big:{ | ||
476 | int segments_per_1000_inch = 1; /* non-zero default for switch */ | ||
477 | switch (ft_qic_std) { | ||
478 | case QIC_TAPE_QIC40: | ||
479 | segments_per_1000_inch = 332; | ||
480 | break; | ||
481 | case QIC_TAPE_QIC80: | ||
482 | segments_per_1000_inch = 488; | ||
483 | break; | ||
484 | case QIC_TAPE_QIC3010: | ||
485 | segments_per_1000_inch = 730; | ||
486 | break; | ||
487 | case QIC_TAPE_QIC3020: | ||
488 | segments_per_1000_inch = 1430; | ||
489 | break; | ||
490 | default: | ||
491 | TRACE_ABORT(-EIO, ft_t_bug, | ||
492 | "%x QIC-standard with fmt-code %d, please report", | ||
493 | ft_qic_std, ft_format_code); | ||
494 | } | ||
495 | new_tape_len = ((1000 * ft_segments_per_track + | ||
496 | (segments_per_1000_inch - 1)) / | ||
497 | segments_per_1000_inch); | ||
498 | break; | ||
499 | } | ||
500 | default: | ||
501 | TRACE_ABORT(-EIO, ft_t_err, | ||
502 | "unknown tape format, please report !"); | ||
503 | } | ||
504 | if (new_tape_len != ftape_tape_len) { | ||
505 | ftape_tape_len = new_tape_len; | ||
506 | TRACE(ft_t_info, "calculated tape length is %d ft", | ||
507 | ftape_tape_len); | ||
508 | ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); | ||
509 | } | ||
510 | if (ft_segments_per_track == 0 && ft_tracks_per_tape == 0 && | ||
511 | max_floppy_side == 0 && max_floppy_track == 0 && | ||
512 | max_floppy_sector == 0) { | ||
513 | /* QIC-40 Rev E and earlier has no values in the header. | ||
514 | */ | ||
515 | ft_segments_per_track = 68; | ||
516 | ft_tracks_per_tape = 20; | ||
517 | max_floppy_side = 1; | ||
518 | max_floppy_track = 169; | ||
519 | max_floppy_sector = 128; | ||
520 | } | ||
521 | /* This test will compensate for the wrong parameter on tapes | ||
522 | * formatted by Conner software. | ||
523 | */ | ||
524 | if (ft_segments_per_track == 150 && | ||
525 | ft_tracks_per_tape == 28 && | ||
526 | max_floppy_side == 7 && | ||
527 | max_floppy_track == 149 && | ||
528 | max_floppy_sector == 128) { | ||
529 | TRACE(ft_t_info, "the famous CONNER bug: max_floppy_side off by one !"); | ||
530 | max_floppy_side = 6; | ||
531 | } | ||
532 | /* These tests will compensate for the wrong parameter on tapes | ||
533 | * formatted by ComByte Windows software. | ||
534 | * | ||
535 | * First, for 205 foot tapes | ||
536 | */ | ||
537 | if (ft_segments_per_track == 100 && | ||
538 | ft_tracks_per_tape == 28 && | ||
539 | max_floppy_side == 9 && | ||
540 | max_floppy_track == 149 && | ||
541 | max_floppy_sector == 128) { | ||
542 | TRACE(ft_t_info, "the ComByte bug: max_floppy_side incorrect!"); | ||
543 | max_floppy_side = 4; | ||
544 | } | ||
545 | /* Next, for 307 foot tapes. */ | ||
546 | if (ft_segments_per_track == 150 && | ||
547 | ft_tracks_per_tape == 28 && | ||
548 | max_floppy_side == 9 && | ||
549 | max_floppy_track == 149 && | ||
550 | max_floppy_sector == 128) { | ||
551 | TRACE(ft_t_info, "the ComByte bug: max_floppy_side incorrect!"); | ||
552 | max_floppy_side = 6; | ||
553 | } | ||
554 | /* This test will compensate for the wrong parameter on tapes | ||
555 | * formatted by Colorado Windows software. | ||
556 | */ | ||
557 | if (ft_segments_per_track == 150 && | ||
558 | ft_tracks_per_tape == 28 && | ||
559 | max_floppy_side == 6 && | ||
560 | max_floppy_track == 150 && | ||
561 | max_floppy_sector == 128) { | ||
562 | TRACE(ft_t_info, "the famous Colorado bug: max_floppy_track off by one !"); | ||
563 | max_floppy_track = 149; | ||
564 | } | ||
565 | ftape_segments_per_head = ((max_floppy_sector/FT_SECTORS_PER_SEGMENT) * | ||
566 | (max_floppy_track + 1)); | ||
567 | /* This test will compensate for some bug reported by Dima | ||
568 | * Brodsky. Seems to be a Colorado bug, either. (freebee | ||
569 | * Imation tape shipped together with Colorado T3000 | ||
570 | */ | ||
571 | if ((ft_format_code == fmt_var || ft_format_code == fmt_big) && | ||
572 | ft_tracks_per_tape == 50 && | ||
573 | max_floppy_side == 54 && | ||
574 | max_floppy_track == 255 && | ||
575 | max_floppy_sector == 128) { | ||
576 | TRACE(ft_t_info, "the famous ??? bug: max_floppy_track off by one !"); | ||
577 | max_floppy_track = 254; | ||
578 | } | ||
579 | /* | ||
580 | * Verify drive_configuration with tape parameters | ||
581 | */ | ||
582 | if (ftape_segments_per_head == 0 || ftape_segments_per_cylinder == 0 || | ||
583 | ((ft_segments_per_track * ft_tracks_per_tape - 1) / ftape_segments_per_head | ||
584 | != max_floppy_side) || | ||
585 | (ftape_segments_per_head / ftape_segments_per_cylinder - 1 != max_floppy_track) || | ||
586 | (ftape_segments_per_cylinder * FT_SECTORS_PER_SEGMENT != max_floppy_sector) | ||
587 | #ifdef TESTING | ||
588 | || ((ft_format_code == fmt_var || ft_format_code == fmt_big) && | ||
589 | (max_floppy_track != 254 || max_floppy_sector != 128)) | ||
590 | #endif | ||
591 | ) { | ||
592 | char segperheadz = ftape_segments_per_head ? ' ' : '?'; | ||
593 | char segpercylz = ftape_segments_per_cylinder ? ' ' : '?'; | ||
594 | TRACE(ft_t_err,"Tape parameters inconsistency, please report"); | ||
595 | TRACE(ft_t_err, "reported = %d/%d/%d/%d/%d/%d", | ||
596 | ft_format_code, | ||
597 | ft_segments_per_track, | ||
598 | ft_tracks_per_tape, | ||
599 | max_floppy_side, | ||
600 | max_floppy_track, | ||
601 | max_floppy_sector); | ||
602 | TRACE(ft_t_err, "required = %d/%d/%d/%d%c/%d%c/%d", | ||
603 | ft_format_code, | ||
604 | ft_segments_per_track, | ||
605 | ft_tracks_per_tape, | ||
606 | ftape_segments_per_head ? | ||
607 | ((ft_segments_per_track * ft_tracks_per_tape -1) / | ||
608 | ftape_segments_per_head ) : | ||
609 | (ft_segments_per_track * ft_tracks_per_tape -1), | ||
610 | segperheadz, | ||
611 | ftape_segments_per_cylinder ? | ||
612 | (ftape_segments_per_head / | ||
613 | ftape_segments_per_cylinder - 1 ) : | ||
614 | ftape_segments_per_head - 1, | ||
615 | segpercylz, | ||
616 | (ftape_segments_per_cylinder * FT_SECTORS_PER_SEGMENT)); | ||
617 | TRACE_EXIT -EIO; | ||
618 | } | ||
619 | ftape_extract_bad_sector_map(address); | ||
620 | TRACE_EXIT 0; | ||
621 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-read.h b/drivers/char/ftape/lowlevel/ftape-read.h deleted file mode 100644 index 069f99f2a984..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-read.h +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | #ifndef _FTAPE_READ_H | ||
2 | #define _FTAPE_READ_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-read.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:22 $ | ||
26 | * | ||
27 | * This file contains the definitions for the read functions | ||
28 | * for the QIC-117 floppy-tape driver for Linux. | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | /* ftape-read.c defined global functions. | ||
33 | */ | ||
34 | typedef enum { | ||
35 | FT_RD_SINGLE = 0, | ||
36 | FT_RD_AHEAD = 1, | ||
37 | } ft_read_mode_t; | ||
38 | |||
39 | extern int ftape_read_header_segment(__u8 *address); | ||
40 | extern int ftape_decode_header_segment(__u8 *address); | ||
41 | extern int ftape_read_segment_fraction(const int segment, | ||
42 | void *address, | ||
43 | const ft_read_mode_t read_mode, | ||
44 | const int start, | ||
45 | const int size); | ||
46 | #define ftape_read_segment(segment, address, read_mode) \ | ||
47 | ftape_read_segment_fraction(segment, address, read_mode, \ | ||
48 | 0, FT_SEGMENT_SIZE) | ||
49 | extern void ftape_zap_read_buffers(void); | ||
50 | |||
51 | #endif /* _FTAPE_READ_H */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-rw.c b/drivers/char/ftape/lowlevel/ftape-rw.c deleted file mode 100644 index c0d6dc2cbfd3..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-rw.c +++ /dev/null | |||
@@ -1,1092 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-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: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-rw.c,v $ | ||
21 | * $Revision: 1.7 $ | ||
22 | * $Date: 1997/10/28 14:26:49 $ | ||
23 | * | ||
24 | * This file contains some common code for the segment read and | ||
25 | * segment write routines for the QIC-117 floppy-tape driver for | ||
26 | * Linux. | ||
27 | */ | ||
28 | |||
29 | #include <linux/string.h> | ||
30 | #include <linux/errno.h> | ||
31 | |||
32 | #include <linux/ftape.h> | ||
33 | #include <linux/qic117.h> | ||
34 | #include "../lowlevel/ftape-tracing.h" | ||
35 | #include "../lowlevel/ftape-rw.h" | ||
36 | #include "../lowlevel/fdc-io.h" | ||
37 | #include "../lowlevel/ftape-init.h" | ||
38 | #include "../lowlevel/ftape-io.h" | ||
39 | #include "../lowlevel/ftape-ctl.h" | ||
40 | #include "../lowlevel/ftape-read.h" | ||
41 | #include "../lowlevel/ftape-ecc.h" | ||
42 | #include "../lowlevel/ftape-bsm.h" | ||
43 | |||
44 | /* Global vars. | ||
45 | */ | ||
46 | int ft_nr_buffers; | ||
47 | buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS]; | ||
48 | static volatile int ft_head; | ||
49 | static volatile int ft_tail; /* not volatile but need same type as head */ | ||
50 | int fdc_setup_error; | ||
51 | location_record ft_location = {-1, 0}; | ||
52 | volatile int ftape_tape_running; | ||
53 | |||
54 | /* Local vars. | ||
55 | */ | ||
56 | static int overrun_count_offset; | ||
57 | static int inhibit_correction; | ||
58 | |||
59 | /* maxmimal allowed overshoot when fast seeking | ||
60 | */ | ||
61 | #define OVERSHOOT_LIMIT 10 | ||
62 | |||
63 | /* Increment cyclic buffer nr. | ||
64 | */ | ||
65 | buffer_struct *ftape_next_buffer(ft_buffer_queue_t pos) | ||
66 | { | ||
67 | switch (pos) { | ||
68 | case ft_queue_head: | ||
69 | if (++ft_head >= ft_nr_buffers) { | ||
70 | ft_head = 0; | ||
71 | } | ||
72 | return ft_buffer[ft_head]; | ||
73 | case ft_queue_tail: | ||
74 | if (++ft_tail >= ft_nr_buffers) { | ||
75 | ft_tail = 0; | ||
76 | } | ||
77 | return ft_buffer[ft_tail]; | ||
78 | default: | ||
79 | return NULL; | ||
80 | } | ||
81 | } | ||
82 | int ftape_buffer_id(ft_buffer_queue_t pos) | ||
83 | { | ||
84 | switch(pos) { | ||
85 | case ft_queue_head: return ft_head; | ||
86 | case ft_queue_tail: return ft_tail; | ||
87 | default: return -1; | ||
88 | } | ||
89 | } | ||
90 | buffer_struct *ftape_get_buffer(ft_buffer_queue_t pos) | ||
91 | { | ||
92 | switch(pos) { | ||
93 | case ft_queue_head: return ft_buffer[ft_head]; | ||
94 | case ft_queue_tail: return ft_buffer[ft_tail]; | ||
95 | default: return NULL; | ||
96 | } | ||
97 | } | ||
98 | void ftape_reset_buffer(void) | ||
99 | { | ||
100 | ft_head = ft_tail = 0; | ||
101 | } | ||
102 | |||
103 | buffer_state_enum ftape_set_state(buffer_state_enum new_state) | ||
104 | { | ||
105 | buffer_state_enum old_state = ft_driver_state; | ||
106 | |||
107 | ft_driver_state = new_state; | ||
108 | return old_state; | ||
109 | } | ||
110 | /* Calculate Floppy Disk Controller and DMA parameters for a segment. | ||
111 | * head: selects buffer struct in array. | ||
112 | * offset: number of physical sectors to skip (including bad ones). | ||
113 | * count: number of physical sectors to handle (including bad ones). | ||
114 | */ | ||
115 | static int setup_segment(buffer_struct * buff, | ||
116 | int segment_id, | ||
117 | unsigned int sector_offset, | ||
118 | unsigned int sector_count, | ||
119 | int retry) | ||
120 | { | ||
121 | SectorMap offset_mask; | ||
122 | SectorMap mask; | ||
123 | TRACE_FUN(ft_t_any); | ||
124 | |||
125 | buff->segment_id = segment_id; | ||
126 | buff->sector_offset = sector_offset; | ||
127 | buff->remaining = sector_count; | ||
128 | buff->head = segment_id / ftape_segments_per_head; | ||
129 | buff->cyl = (segment_id % ftape_segments_per_head) / ftape_segments_per_cylinder; | ||
130 | buff->sect = (segment_id % ftape_segments_per_cylinder) * FT_SECTORS_PER_SEGMENT + 1; | ||
131 | buff->deleted = 0; | ||
132 | offset_mask = (1 << buff->sector_offset) - 1; | ||
133 | mask = ftape_get_bad_sector_entry(segment_id) & offset_mask; | ||
134 | while (mask) { | ||
135 | if (mask & 1) { | ||
136 | offset_mask >>= 1; /* don't count bad sector */ | ||
137 | } | ||
138 | mask >>= 1; | ||
139 | } | ||
140 | buff->data_offset = count_ones(offset_mask); /* good sectors to skip */ | ||
141 | buff->ptr = buff->address + buff->data_offset * FT_SECTOR_SIZE; | ||
142 | TRACE(ft_t_flow, "data offset = %d sectors", buff->data_offset); | ||
143 | if (retry) { | ||
144 | buff->soft_error_map &= offset_mask; /* keep skipped part */ | ||
145 | } else { | ||
146 | buff->hard_error_map = buff->soft_error_map = 0; | ||
147 | } | ||
148 | buff->bad_sector_map = ftape_get_bad_sector_entry(buff->segment_id); | ||
149 | if (buff->bad_sector_map != 0) { | ||
150 | TRACE(ft_t_noise, "segment: %d, bad sector map: %08lx", | ||
151 | buff->segment_id, (long)buff->bad_sector_map); | ||
152 | } else { | ||
153 | TRACE(ft_t_flow, "segment: %d", buff->segment_id); | ||
154 | } | ||
155 | if (buff->sector_offset > 0) { | ||
156 | buff->bad_sector_map >>= buff->sector_offset; | ||
157 | } | ||
158 | if (buff->sector_offset != 0 || buff->remaining != FT_SECTORS_PER_SEGMENT) { | ||
159 | TRACE(ft_t_flow, "sector offset = %d, count = %d", | ||
160 | buff->sector_offset, buff->remaining); | ||
161 | } | ||
162 | /* Segments with 3 or less sectors are not written with valid | ||
163 | * data because there is no space left for the ecc. The | ||
164 | * data written is whatever happens to be in the buffer. | ||
165 | * Reading such a segment will return a zero byte-count. | ||
166 | * To allow us to read/write segments with all bad sectors | ||
167 | * we fake one readable sector in the segment. This | ||
168 | * prevents having to handle these segments in a very | ||
169 | * special way. It is not important if the reading of this | ||
170 | * bad sector fails or not (the data is ignored). It is | ||
171 | * only read to keep the driver running. | ||
172 | * | ||
173 | * The QIC-40/80 spec. has no information on how to handle | ||
174 | * this case, so this is my interpretation. | ||
175 | */ | ||
176 | if (buff->bad_sector_map == EMPTY_SEGMENT) { | ||
177 | TRACE(ft_t_flow, "empty segment %d, fake first sector good", | ||
178 | buff->segment_id); | ||
179 | if (buff->ptr != buff->address) { | ||
180 | TRACE(ft_t_bug, "This is a bug: %p/%p", | ||
181 | buff->ptr, buff->address); | ||
182 | } | ||
183 | buff->bad_sector_map = FAKE_SEGMENT; | ||
184 | } | ||
185 | fdc_setup_error = 0; | ||
186 | buff->next_segment = segment_id + 1; | ||
187 | TRACE_EXIT 0; | ||
188 | } | ||
189 | |||
190 | /* Calculate Floppy Disk Controller and DMA parameters for a new segment. | ||
191 | */ | ||
192 | int ftape_setup_new_segment(buffer_struct * buff, int segment_id, int skip) | ||
193 | { | ||
194 | int result = 0; | ||
195 | static int old_segment_id = -1; | ||
196 | static buffer_state_enum old_ft_driver_state = idle; | ||
197 | int retry = 0; | ||
198 | unsigned offset = 0; | ||
199 | int count = FT_SECTORS_PER_SEGMENT; | ||
200 | TRACE_FUN(ft_t_flow); | ||
201 | |||
202 | TRACE(ft_t_flow, "%s segment %d (old = %d)", | ||
203 | (ft_driver_state == reading || ft_driver_state == verifying) | ||
204 | ? "reading" : "writing", | ||
205 | segment_id, old_segment_id); | ||
206 | if (ft_driver_state != old_ft_driver_state) { /* when verifying */ | ||
207 | old_segment_id = -1; | ||
208 | old_ft_driver_state = ft_driver_state; | ||
209 | } | ||
210 | if (segment_id == old_segment_id) { | ||
211 | ++buff->retry; | ||
212 | ++ft_history.retries; | ||
213 | TRACE(ft_t_flow, "setting up for retry nr %d", buff->retry); | ||
214 | retry = 1; | ||
215 | if (skip && buff->skip > 0) { /* allow skip on retry */ | ||
216 | offset = buff->skip; | ||
217 | count -= offset; | ||
218 | TRACE(ft_t_flow, "skipping %d sectors", offset); | ||
219 | } | ||
220 | } else { | ||
221 | buff->retry = 0; | ||
222 | buff->skip = 0; | ||
223 | old_segment_id = segment_id; | ||
224 | } | ||
225 | result = setup_segment(buff, segment_id, offset, count, retry); | ||
226 | TRACE_EXIT result; | ||
227 | } | ||
228 | |||
229 | /* Determine size of next cluster of good sectors. | ||
230 | */ | ||
231 | int ftape_calc_next_cluster(buffer_struct * buff) | ||
232 | { | ||
233 | /* Skip bad sectors. | ||
234 | */ | ||
235 | while (buff->remaining > 0 && (buff->bad_sector_map & 1) != 0) { | ||
236 | buff->bad_sector_map >>= 1; | ||
237 | ++buff->sector_offset; | ||
238 | --buff->remaining; | ||
239 | } | ||
240 | /* Find next cluster of good sectors | ||
241 | */ | ||
242 | if (buff->bad_sector_map == 0) { /* speed up */ | ||
243 | buff->sector_count = buff->remaining; | ||
244 | } else { | ||
245 | SectorMap map = buff->bad_sector_map; | ||
246 | |||
247 | buff->sector_count = 0; | ||
248 | while (buff->sector_count < buff->remaining && (map & 1) == 0) { | ||
249 | ++buff->sector_count; | ||
250 | map >>= 1; | ||
251 | } | ||
252 | } | ||
253 | return buff->sector_count; | ||
254 | } | ||
255 | |||
256 | /* if just passed the last segment on a track, wait for BOT | ||
257 | * or EOT mark. | ||
258 | */ | ||
259 | int ftape_handle_logical_eot(void) | ||
260 | { | ||
261 | TRACE_FUN(ft_t_flow); | ||
262 | |||
263 | if (ft_runner_status == logical_eot) { | ||
264 | int status; | ||
265 | |||
266 | TRACE(ft_t_noise, "tape at logical EOT"); | ||
267 | TRACE_CATCH(ftape_ready_wait(ftape_timeout.seek, &status),); | ||
268 | if ((status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) == 0) { | ||
269 | TRACE_ABORT(-EIO, ft_t_err, "eot/bot not reached"); | ||
270 | } | ||
271 | ft_runner_status = end_of_tape; | ||
272 | } | ||
273 | if (ft_runner_status == end_of_tape) { | ||
274 | TRACE(ft_t_noise, "runner stopped because of logical EOT"); | ||
275 | ft_runner_status = idle; | ||
276 | } | ||
277 | TRACE_EXIT 0; | ||
278 | } | ||
279 | |||
280 | static int check_bot_eot(int status) | ||
281 | { | ||
282 | TRACE_FUN(ft_t_flow); | ||
283 | |||
284 | if (status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) { | ||
285 | ft_location.bot = ((ft_location.track & 1) == 0 ? | ||
286 | (status & QIC_STATUS_AT_BOT) != 0: | ||
287 | (status & QIC_STATUS_AT_EOT) != 0); | ||
288 | ft_location.eot = !ft_location.bot; | ||
289 | ft_location.segment = (ft_location.track + | ||
290 | (ft_location.bot ? 0 : 1)) * ft_segments_per_track - 1; | ||
291 | ft_location.sector = -1; | ||
292 | ft_location.known = 1; | ||
293 | TRACE(ft_t_flow, "tape at logical %s", | ||
294 | ft_location.bot ? "bot" : "eot"); | ||
295 | TRACE(ft_t_flow, "segment = %d", ft_location.segment); | ||
296 | } else { | ||
297 | ft_location.known = 0; | ||
298 | } | ||
299 | TRACE_EXIT ft_location.known; | ||
300 | } | ||
301 | |||
302 | /* Read Id of first sector passing tape head. | ||
303 | */ | ||
304 | static int ftape_read_id(void) | ||
305 | { | ||
306 | int status; | ||
307 | __u8 out[2]; | ||
308 | TRACE_FUN(ft_t_any); | ||
309 | |||
310 | /* Assume tape is running on entry, be able to handle | ||
311 | * situation where it stopped or is stopping. | ||
312 | */ | ||
313 | ft_location.known = 0; /* default is location not known */ | ||
314 | out[0] = FDC_READID; | ||
315 | out[1] = ft_drive_sel; | ||
316 | TRACE_CATCH(fdc_command(out, 2),); | ||
317 | switch (fdc_interrupt_wait(20 * FT_SECOND)) { | ||
318 | case 0: | ||
319 | if (fdc_sect == 0) { | ||
320 | if (ftape_report_drive_status(&status) >= 0 && | ||
321 | (status & QIC_STATUS_READY)) { | ||
322 | ftape_tape_running = 0; | ||
323 | TRACE(ft_t_flow, "tape has stopped"); | ||
324 | check_bot_eot(status); | ||
325 | } | ||
326 | } else { | ||
327 | ft_location.known = 1; | ||
328 | ft_location.segment = (ftape_segments_per_head | ||
329 | * fdc_head | ||
330 | + ftape_segments_per_cylinder | ||
331 | * fdc_cyl | ||
332 | + (fdc_sect - 1) | ||
333 | / FT_SECTORS_PER_SEGMENT); | ||
334 | ft_location.sector = ((fdc_sect - 1) | ||
335 | % FT_SECTORS_PER_SEGMENT); | ||
336 | ft_location.eot = ft_location.bot = 0; | ||
337 | } | ||
338 | break; | ||
339 | case -ETIME: | ||
340 | /* Didn't find id on tape, must be near end: Wait | ||
341 | * until stopped. | ||
342 | */ | ||
343 | if (ftape_ready_wait(FT_FOREVER, &status) >= 0) { | ||
344 | ftape_tape_running = 0; | ||
345 | TRACE(ft_t_flow, "tape has stopped"); | ||
346 | check_bot_eot(status); | ||
347 | } | ||
348 | break; | ||
349 | default: | ||
350 | /* Interrupted or otherwise failing | ||
351 | * fdc_interrupt_wait() | ||
352 | */ | ||
353 | TRACE(ft_t_err, "fdc_interrupt_wait failed"); | ||
354 | break; | ||
355 | } | ||
356 | if (!ft_location.known) { | ||
357 | TRACE_ABORT(-EIO, ft_t_flow, "no id found"); | ||
358 | } | ||
359 | if (ft_location.sector == 0) { | ||
360 | TRACE(ft_t_flow, "passing segment %d/%d", | ||
361 | ft_location.segment, ft_location.sector); | ||
362 | } else { | ||
363 | TRACE(ft_t_fdc_dma, "passing segment %d/%d", | ||
364 | ft_location.segment, ft_location.sector); | ||
365 | } | ||
366 | TRACE_EXIT 0; | ||
367 | } | ||
368 | |||
369 | static int logical_forward(void) | ||
370 | { | ||
371 | ftape_tape_running = 1; | ||
372 | return ftape_command(QIC_LOGICAL_FORWARD); | ||
373 | } | ||
374 | |||
375 | int ftape_stop_tape(int *pstatus) | ||
376 | { | ||
377 | int retry = 0; | ||
378 | int result; | ||
379 | TRACE_FUN(ft_t_flow); | ||
380 | |||
381 | do { | ||
382 | result = ftape_command_wait(QIC_STOP_TAPE, | ||
383 | ftape_timeout.stop, pstatus); | ||
384 | if (result == 0) { | ||
385 | if ((*pstatus & QIC_STATUS_READY) == 0) { | ||
386 | result = -EIO; | ||
387 | } else { | ||
388 | ftape_tape_running = 0; | ||
389 | } | ||
390 | } | ||
391 | } while (result < 0 && ++retry <= 3); | ||
392 | if (result < 0) { | ||
393 | TRACE(ft_t_err, "failed ! (fatal)"); | ||
394 | } | ||
395 | TRACE_EXIT result; | ||
396 | } | ||
397 | |||
398 | int ftape_dumb_stop(void) | ||
399 | { | ||
400 | int result; | ||
401 | int status; | ||
402 | TRACE_FUN(ft_t_flow); | ||
403 | |||
404 | /* Abort current fdc operation if it's busy (probably read | ||
405 | * or write operation pending) with a reset. | ||
406 | */ | ||
407 | if (fdc_ready_wait(100 /* usec */) < 0) { | ||
408 | TRACE(ft_t_noise, "aborting fdc operation"); | ||
409 | fdc_reset(); | ||
410 | } | ||
411 | /* Reading id's after the last segment on a track may fail | ||
412 | * but eventually the drive will become ready (logical eot). | ||
413 | */ | ||
414 | result = ftape_report_drive_status(&status); | ||
415 | ft_location.known = 0; | ||
416 | do { | ||
417 | if (result == 0 && status & QIC_STATUS_READY) { | ||
418 | /* Tape is not running any more. | ||
419 | */ | ||
420 | TRACE(ft_t_noise, "tape already halted"); | ||
421 | check_bot_eot(status); | ||
422 | ftape_tape_running = 0; | ||
423 | } else if (ftape_tape_running) { | ||
424 | /* Tape is (was) still moving. | ||
425 | */ | ||
426 | #ifdef TESTING | ||
427 | ftape_read_id(); | ||
428 | #endif | ||
429 | result = ftape_stop_tape(&status); | ||
430 | } else { | ||
431 | /* Tape not yet ready but stopped. | ||
432 | */ | ||
433 | result = ftape_ready_wait(ftape_timeout.pause,&status); | ||
434 | } | ||
435 | } while (ftape_tape_running | ||
436 | && !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK))); | ||
437 | #ifndef TESTING | ||
438 | ft_location.known = 0; | ||
439 | #endif | ||
440 | if (ft_runner_status == aborting || ft_runner_status == do_abort) { | ||
441 | ft_runner_status = idle; | ||
442 | } | ||
443 | TRACE_EXIT result; | ||
444 | } | ||
445 | |||
446 | /* Wait until runner has finished tail buffer. | ||
447 | * | ||
448 | */ | ||
449 | int ftape_wait_segment(buffer_state_enum state) | ||
450 | { | ||
451 | int status; | ||
452 | int result = 0; | ||
453 | TRACE_FUN(ft_t_flow); | ||
454 | |||
455 | while (ft_buffer[ft_tail]->status == state) { | ||
456 | TRACE(ft_t_flow, "state: %d", ft_buffer[ft_tail]->status); | ||
457 | /* First buffer still being worked on, wait up to timeout. | ||
458 | * | ||
459 | * Note: we check two times for being killed. 50 | ||
460 | * seconds are quite long. Note that | ||
461 | * fdc_interrupt_wait() is not killable by any | ||
462 | * means. ftape_read_segment() wants us to return | ||
463 | * -EINTR in case of a signal. | ||
464 | */ | ||
465 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
466 | result = fdc_interrupt_wait(50 * FT_SECOND); | ||
467 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
468 | if (result < 0) { | ||
469 | TRACE_ABORT(result, | ||
470 | ft_t_err, "fdc_interrupt_wait failed"); | ||
471 | } | ||
472 | if (fdc_setup_error) { | ||
473 | /* recover... FIXME */ | ||
474 | TRACE_ABORT(-EIO, ft_t_err, "setup error"); | ||
475 | } | ||
476 | } | ||
477 | if (ft_buffer[ft_tail]->status != error) { | ||
478 | TRACE_EXIT 0; | ||
479 | } | ||
480 | TRACE_CATCH(ftape_report_drive_status(&status),); | ||
481 | TRACE(ft_t_noise, "ftape_report_drive_status: 0x%02x", status); | ||
482 | if ((status & QIC_STATUS_READY) && | ||
483 | (status & QIC_STATUS_ERROR)) { | ||
484 | unsigned int error; | ||
485 | qic117_cmd_t command; | ||
486 | |||
487 | /* Report and clear error state. | ||
488 | * In case the drive can't operate at the selected | ||
489 | * rate, select the next lower data rate. | ||
490 | */ | ||
491 | ftape_report_error(&error, &command, 1); | ||
492 | if (error == 31 && command == QIC_LOGICAL_FORWARD) { | ||
493 | /* drive does not accept this data rate */ | ||
494 | if (ft_data_rate > 250) { | ||
495 | TRACE(ft_t_info, | ||
496 | "Probable data rate conflict"); | ||
497 | TRACE(ft_t_info, | ||
498 | "Lowering data rate to %d Kbps", | ||
499 | ft_data_rate / 2); | ||
500 | ftape_half_data_rate(); | ||
501 | if (ft_buffer[ft_tail]->retry > 0) { | ||
502 | /* give it a chance */ | ||
503 | --ft_buffer[ft_tail]->retry; | ||
504 | } | ||
505 | } else { | ||
506 | /* no rate is accepted... */ | ||
507 | TRACE(ft_t_err, "We're dead :("); | ||
508 | } | ||
509 | } else { | ||
510 | TRACE(ft_t_err, "Unknown error"); | ||
511 | } | ||
512 | TRACE_EXIT -EIO; /* g.p. error */ | ||
513 | } | ||
514 | TRACE_EXIT 0; | ||
515 | } | ||
516 | |||
517 | /* forward */ static int seek_forward(int segment_id, int fast); | ||
518 | |||
519 | static int fast_seek(int count, int reverse) | ||
520 | { | ||
521 | int result = 0; | ||
522 | int status; | ||
523 | TRACE_FUN(ft_t_flow); | ||
524 | |||
525 | if (count > 0) { | ||
526 | /* If positioned at begin or end of tape, fast seeking needs | ||
527 | * special treatment. | ||
528 | * Starting from logical bot needs a (slow) seek to the first | ||
529 | * segment before the high speed seek. Most drives do this | ||
530 | * automatically but some older don't, so we treat them | ||
531 | * all the same. | ||
532 | * Starting from logical eot is even more difficult because | ||
533 | * we cannot (slow) reverse seek to the last segment. | ||
534 | * TO BE IMPLEMENTED. | ||
535 | */ | ||
536 | inhibit_correction = 0; | ||
537 | if (ft_location.known && | ||
538 | ((ft_location.bot && !reverse) || | ||
539 | (ft_location.eot && reverse))) { | ||
540 | if (!reverse) { | ||
541 | /* (slow) skip to first segment on a track | ||
542 | */ | ||
543 | seek_forward(ft_location.track * ft_segments_per_track, 0); | ||
544 | --count; | ||
545 | } else { | ||
546 | /* When seeking backwards from | ||
547 | * end-of-tape the number of erased | ||
548 | * gaps found seems to be higher than | ||
549 | * expected. Therefor the drive must | ||
550 | * skip some more segments than | ||
551 | * calculated, but we don't know how | ||
552 | * many. Thus we will prevent the | ||
553 | * re-calculation of offset and | ||
554 | * overshoot when seeking backwards. | ||
555 | */ | ||
556 | inhibit_correction = 1; | ||
557 | count += 3; /* best guess */ | ||
558 | } | ||
559 | } | ||
560 | } else { | ||
561 | TRACE(ft_t_flow, "warning: zero or negative count: %d", count); | ||
562 | } | ||
563 | if (count > 0) { | ||
564 | int i; | ||
565 | int nibbles = count > 255 ? 3 : 2; | ||
566 | |||
567 | if (count > 4095) { | ||
568 | TRACE(ft_t_noise, "skipping clipped at 4095 segment"); | ||
569 | count = 4095; | ||
570 | } | ||
571 | /* Issue this tape command first. */ | ||
572 | if (!reverse) { | ||
573 | TRACE(ft_t_noise, "skipping %d segment(s)", count); | ||
574 | result = ftape_command(nibbles == 3 ? | ||
575 | QIC_SKIP_EXTENDED_FORWARD : QIC_SKIP_FORWARD); | ||
576 | } else { | ||
577 | TRACE(ft_t_noise, "backing up %d segment(s)", count); | ||
578 | result = ftape_command(nibbles == 3 ? | ||
579 | QIC_SKIP_EXTENDED_REVERSE : QIC_SKIP_REVERSE); | ||
580 | } | ||
581 | if (result < 0) { | ||
582 | TRACE(ft_t_noise, "Skip command failed"); | ||
583 | } else { | ||
584 | --count; /* 0 means one gap etc. */ | ||
585 | for (i = 0; i < nibbles; ++i) { | ||
586 | if (result >= 0) { | ||
587 | result = ftape_parameter(count & 15); | ||
588 | count /= 16; | ||
589 | } | ||
590 | } | ||
591 | result = ftape_ready_wait(ftape_timeout.rewind, &status); | ||
592 | if (result >= 0) { | ||
593 | ftape_tape_running = 0; | ||
594 | } | ||
595 | } | ||
596 | } | ||
597 | TRACE_EXIT result; | ||
598 | } | ||
599 | |||
600 | static int validate(int id) | ||
601 | { | ||
602 | /* Check to see if position found is off-track as reported | ||
603 | * once. Because all tracks in one direction lie next to | ||
604 | * each other, if off-track the error will be approximately | ||
605 | * 2 * ft_segments_per_track. | ||
606 | */ | ||
607 | if (ft_location.track == -1) { | ||
608 | return 1; /* unforseen situation, don't generate error */ | ||
609 | } else { | ||
610 | /* Use margin of ft_segments_per_track on both sides | ||
611 | * because ftape needs some margin and the error we're | ||
612 | * looking for is much larger ! | ||
613 | */ | ||
614 | int lo = (ft_location.track - 1) * ft_segments_per_track; | ||
615 | int hi = (ft_location.track + 2) * ft_segments_per_track; | ||
616 | |||
617 | return (id >= lo && id < hi); | ||
618 | } | ||
619 | } | ||
620 | |||
621 | static int seek_forward(int segment_id, int fast) | ||
622 | { | ||
623 | int failures = 0; | ||
624 | int count; | ||
625 | static int margin = 1; /* fixed: stop this before target */ | ||
626 | static int overshoot = 1; | ||
627 | static int min_count = 8; | ||
628 | int expected = -1; | ||
629 | int target = segment_id - margin; | ||
630 | int fast_seeking; | ||
631 | int prev_segment = ft_location.segment; | ||
632 | TRACE_FUN(ft_t_flow); | ||
633 | |||
634 | if (!ft_location.known) { | ||
635 | TRACE_ABORT(-EIO, ft_t_err, | ||
636 | "fatal: cannot seek from unknown location"); | ||
637 | } | ||
638 | if (!validate(segment_id)) { | ||
639 | ftape_sleep(1 * FT_SECOND); | ||
640 | ft_failure = 1; | ||
641 | TRACE_ABORT(-EIO, ft_t_err, | ||
642 | "fatal: head off track (bad hardware?)"); | ||
643 | } | ||
644 | TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", | ||
645 | ft_location.segment, ft_location.sector,segment_id,margin); | ||
646 | count = target - ft_location.segment - overshoot; | ||
647 | fast_seeking = (fast && | ||
648 | count > (min_count + (ft_location.bot ? 1 : 0))); | ||
649 | if (fast_seeking) { | ||
650 | TRACE(ft_t_noise, "fast skipping %d segments", count); | ||
651 | expected = segment_id - margin; | ||
652 | fast_seek(count, 0); | ||
653 | } | ||
654 | if (!ftape_tape_running) { | ||
655 | logical_forward(); | ||
656 | } | ||
657 | while (ft_location.segment < segment_id) { | ||
658 | /* This requires at least one sector in a (bad) segment to | ||
659 | * have a valid and readable sector id ! | ||
660 | * It looks like this is not guaranteed, so we must try | ||
661 | * to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!! | ||
662 | */ | ||
663 | if (ftape_read_id() < 0 || !ft_location.known || | ||
664 | sigtestsetmask(¤t->pending.signal, _DONT_BLOCK)) { | ||
665 | ft_location.known = 0; | ||
666 | if (!ftape_tape_running || | ||
667 | ++failures > FT_SECTORS_PER_SEGMENT) { | ||
668 | TRACE_ABORT(-EIO, ft_t_err, | ||
669 | "read_id failed completely"); | ||
670 | } | ||
671 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
672 | TRACE(ft_t_flow, "read_id failed, retry (%d)", | ||
673 | failures); | ||
674 | continue; | ||
675 | } | ||
676 | if (fast_seeking) { | ||
677 | TRACE(ft_t_noise, "ended at %d/%d (%d,%d)", | ||
678 | ft_location.segment, ft_location.sector, | ||
679 | overshoot, inhibit_correction); | ||
680 | if (!inhibit_correction && | ||
681 | (ft_location.segment < expected || | ||
682 | ft_location.segment > expected + margin)) { | ||
683 | int error = ft_location.segment - expected; | ||
684 | TRACE(ft_t_noise, | ||
685 | "adjusting overshoot from %d to %d", | ||
686 | overshoot, overshoot + error); | ||
687 | overshoot += error; | ||
688 | /* All overshoots have the same | ||
689 | * direction, so it should never | ||
690 | * become negative, but who knows. | ||
691 | */ | ||
692 | if (overshoot < -5 || | ||
693 | overshoot > OVERSHOOT_LIMIT) { | ||
694 | if (overshoot < 0) { | ||
695 | /* keep sane value */ | ||
696 | overshoot = -5; | ||
697 | } else { | ||
698 | /* keep sane value */ | ||
699 | overshoot = OVERSHOOT_LIMIT; | ||
700 | } | ||
701 | TRACE(ft_t_noise, | ||
702 | "clipped overshoot to %d", | ||
703 | overshoot); | ||
704 | } | ||
705 | } | ||
706 | fast_seeking = 0; | ||
707 | } | ||
708 | if (ft_location.known) { | ||
709 | if (ft_location.segment > prev_segment + 1) { | ||
710 | TRACE(ft_t_noise, | ||
711 | "missed segment %d while skipping", | ||
712 | prev_segment + 1); | ||
713 | } | ||
714 | prev_segment = ft_location.segment; | ||
715 | } | ||
716 | } | ||
717 | if (ft_location.segment > segment_id) { | ||
718 | TRACE_ABORT(-EIO, | ||
719 | ft_t_noise, "failed: skip ended at segment %d/%d", | ||
720 | ft_location.segment, ft_location.sector); | ||
721 | } | ||
722 | TRACE_EXIT 0; | ||
723 | } | ||
724 | |||
725 | static int skip_reverse(int segment_id, int *pstatus) | ||
726 | { | ||
727 | int failures = 0; | ||
728 | static int overshoot = 1; | ||
729 | static int min_rewind = 2; /* 1 + overshoot */ | ||
730 | static const int margin = 1; /* stop this before target */ | ||
731 | int expected = 0; | ||
732 | int count = 1; | ||
733 | int short_seek; | ||
734 | int target = segment_id - margin; | ||
735 | TRACE_FUN(ft_t_flow); | ||
736 | |||
737 | if (ft_location.known && !validate(segment_id)) { | ||
738 | ftape_sleep(1 * FT_SECOND); | ||
739 | ft_failure = 1; | ||
740 | TRACE_ABORT(-EIO, ft_t_err, | ||
741 | "fatal: head off track (bad hardware?)"); | ||
742 | } | ||
743 | do { | ||
744 | if (!ft_location.known) { | ||
745 | TRACE(ft_t_warn, "warning: location not known"); | ||
746 | } | ||
747 | TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", | ||
748 | ft_location.segment, ft_location.sector, | ||
749 | segment_id, margin); | ||
750 | /* min_rewind == 1 + overshoot_when_doing_minimum_rewind | ||
751 | * overshoot == overshoot_when_doing_larger_rewind | ||
752 | * Initially min_rewind == 1 + overshoot, optimization | ||
753 | * of both values will be done separately. | ||
754 | * overshoot and min_rewind can be negative as both are | ||
755 | * sums of three components: | ||
756 | * any_overshoot == rewind_overshoot - | ||
757 | * stop_overshoot - | ||
758 | * start_overshoot | ||
759 | */ | ||
760 | if (ft_location.segment - target - (min_rewind - 1) < 1) { | ||
761 | short_seek = 1; | ||
762 | } else { | ||
763 | count = ft_location.segment - target - overshoot; | ||
764 | short_seek = (count < 1); | ||
765 | } | ||
766 | if (short_seek) { | ||
767 | count = 1; /* do shortest rewind */ | ||
768 | expected = ft_location.segment - min_rewind; | ||
769 | if (expected/ft_segments_per_track != ft_location.track) { | ||
770 | expected = (ft_location.track * | ||
771 | ft_segments_per_track); | ||
772 | } | ||
773 | } else { | ||
774 | expected = target; | ||
775 | } | ||
776 | fast_seek(count, 1); | ||
777 | logical_forward(); | ||
778 | if (ftape_read_id() < 0 || !ft_location.known || | ||
779 | (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { | ||
780 | if ((!ftape_tape_running && !ft_location.known) || | ||
781 | ++failures > FT_SECTORS_PER_SEGMENT) { | ||
782 | TRACE_ABORT(-EIO, ft_t_err, | ||
783 | "read_id failed completely"); | ||
784 | } | ||
785 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
786 | TRACE_CATCH(ftape_report_drive_status(pstatus),); | ||
787 | TRACE(ft_t_noise, "ftape_read_id failed, retry (%d)", | ||
788 | failures); | ||
789 | continue; | ||
790 | } | ||
791 | TRACE(ft_t_noise, "ended at %d/%d (%d,%d,%d)", | ||
792 | ft_location.segment, ft_location.sector, | ||
793 | min_rewind, overshoot, inhibit_correction); | ||
794 | if (!inhibit_correction && | ||
795 | (ft_location.segment < expected || | ||
796 | ft_location.segment > expected + margin)) { | ||
797 | int error = expected - ft_location.segment; | ||
798 | if (short_seek) { | ||
799 | TRACE(ft_t_noise, | ||
800 | "adjusting min_rewind from %d to %d", | ||
801 | min_rewind, min_rewind + error); | ||
802 | min_rewind += error; | ||
803 | if (min_rewind < -5) { | ||
804 | /* is this right ? FIXME ! */ | ||
805 | /* keep sane value */ | ||
806 | min_rewind = -5; | ||
807 | TRACE(ft_t_noise, | ||
808 | "clipped min_rewind to %d", | ||
809 | min_rewind); | ||
810 | } | ||
811 | } else { | ||
812 | TRACE(ft_t_noise, | ||
813 | "adjusting overshoot from %d to %d", | ||
814 | overshoot, overshoot + error); | ||
815 | overshoot += error; | ||
816 | if (overshoot < -5 || | ||
817 | overshoot > OVERSHOOT_LIMIT) { | ||
818 | if (overshoot < 0) { | ||
819 | /* keep sane value */ | ||
820 | overshoot = -5; | ||
821 | } else { | ||
822 | /* keep sane value */ | ||
823 | overshoot = OVERSHOOT_LIMIT; | ||
824 | } | ||
825 | TRACE(ft_t_noise, | ||
826 | "clipped overshoot to %d", | ||
827 | overshoot); | ||
828 | } | ||
829 | } | ||
830 | } | ||
831 | } while (ft_location.segment > segment_id); | ||
832 | if (ft_location.known) { | ||
833 | TRACE(ft_t_noise, "current location: %d/%d", | ||
834 | ft_location.segment, ft_location.sector); | ||
835 | } | ||
836 | TRACE_EXIT 0; | ||
837 | } | ||
838 | |||
839 | static int determine_position(void) | ||
840 | { | ||
841 | int retry = 0; | ||
842 | int status; | ||
843 | int result; | ||
844 | TRACE_FUN(ft_t_flow); | ||
845 | |||
846 | if (!ftape_tape_running) { | ||
847 | /* This should only happen if tape is stopped by isr. | ||
848 | */ | ||
849 | TRACE(ft_t_flow, "waiting for tape stop"); | ||
850 | if (ftape_ready_wait(ftape_timeout.pause, &status) < 0) { | ||
851 | TRACE(ft_t_flow, "drive still running (fatal)"); | ||
852 | ftape_tape_running = 1; /* ? */ | ||
853 | } | ||
854 | } else { | ||
855 | ftape_report_drive_status(&status); | ||
856 | } | ||
857 | if (status & QIC_STATUS_READY) { | ||
858 | /* Drive must be ready to check error state ! | ||
859 | */ | ||
860 | TRACE(ft_t_flow, "drive is ready"); | ||
861 | if (status & QIC_STATUS_ERROR) { | ||
862 | unsigned int error; | ||
863 | qic117_cmd_t command; | ||
864 | |||
865 | /* Report and clear error state, try to continue. | ||
866 | */ | ||
867 | TRACE(ft_t_flow, "error status set"); | ||
868 | ftape_report_error(&error, &command, 1); | ||
869 | ftape_ready_wait(ftape_timeout.reset, &status); | ||
870 | ftape_tape_running = 0; /* ? */ | ||
871 | } | ||
872 | if (check_bot_eot(status)) { | ||
873 | if (ft_location.bot) { | ||
874 | if ((status & QIC_STATUS_READY) == 0) { | ||
875 | /* tape moving away from | ||
876 | * bot/eot, let's see if we | ||
877 | * can catch up with the first | ||
878 | * segment on this track. | ||
879 | */ | ||
880 | } else { | ||
881 | TRACE(ft_t_flow, | ||
882 | "start tape from logical bot"); | ||
883 | logical_forward(); /* start moving */ | ||
884 | } | ||
885 | } else { | ||
886 | if ((status & QIC_STATUS_READY) == 0) { | ||
887 | TRACE(ft_t_noise, "waiting for logical end of track"); | ||
888 | result = ftape_ready_wait(ftape_timeout.reset, &status); | ||
889 | /* error handling needed ? */ | ||
890 | } else { | ||
891 | TRACE(ft_t_noise, | ||
892 | "tape at logical end of track"); | ||
893 | } | ||
894 | } | ||
895 | } else { | ||
896 | TRACE(ft_t_flow, "start tape"); | ||
897 | logical_forward(); /* start moving */ | ||
898 | ft_location.known = 0; /* not cleared by logical forward ! */ | ||
899 | } | ||
900 | } | ||
901 | /* tape should be moving now, start reading id's | ||
902 | */ | ||
903 | while (!ft_location.known && | ||
904 | retry++ < FT_SECTORS_PER_SEGMENT && | ||
905 | (result = ftape_read_id()) < 0) { | ||
906 | |||
907 | TRACE(ft_t_flow, "location unknown"); | ||
908 | |||
909 | /* exit on signal | ||
910 | */ | ||
911 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
912 | |||
913 | /* read-id somehow failed, tape may | ||
914 | * have reached end or some other | ||
915 | * error happened. | ||
916 | */ | ||
917 | TRACE(ft_t_flow, "read-id failed"); | ||
918 | TRACE_CATCH(ftape_report_drive_status(&status),); | ||
919 | TRACE(ft_t_err, "ftape_report_drive_status: 0x%02x", status); | ||
920 | if (status & QIC_STATUS_READY) { | ||
921 | ftape_tape_running = 0; | ||
922 | TRACE(ft_t_noise, "tape stopped for unknown reason! " | ||
923 | "status = 0x%02x", status); | ||
924 | if (status & QIC_STATUS_ERROR || | ||
925 | !check_bot_eot(status)) { | ||
926 | /* oops, tape stopped but not at end! | ||
927 | */ | ||
928 | TRACE_EXIT -EIO; | ||
929 | } | ||
930 | } | ||
931 | } | ||
932 | TRACE(ft_t_flow, | ||
933 | "tape is positioned at segment %d", ft_location.segment); | ||
934 | TRACE_EXIT ft_location.known ? 0 : -EIO; | ||
935 | } | ||
936 | |||
937 | /* Get the tape running and position it just before the | ||
938 | * requested segment. | ||
939 | * Seek tape-track and reposition as needed. | ||
940 | */ | ||
941 | int ftape_start_tape(int segment_id, int sector_offset) | ||
942 | { | ||
943 | int track = segment_id / ft_segments_per_track; | ||
944 | int result = -EIO; | ||
945 | int status; | ||
946 | static int last_segment = -1; | ||
947 | static int bad_bus_timing = 0; | ||
948 | /* number of segments passing the head between starting the tape | ||
949 | * and being able to access the first sector. | ||
950 | */ | ||
951 | static int start_offset = 1; | ||
952 | int retry; | ||
953 | TRACE_FUN(ft_t_flow); | ||
954 | |||
955 | /* If sector_offset > 0, seek into wanted segment instead of | ||
956 | * into previous. | ||
957 | * This allows error recovery if a part of the segment is bad | ||
958 | * (erased) causing the tape drive to generate an index pulse | ||
959 | * thus causing a no-data error before the requested sector | ||
960 | * is reached. | ||
961 | */ | ||
962 | ftape_tape_running = 0; | ||
963 | TRACE(ft_t_noise, "target segment: %d/%d%s", segment_id, sector_offset, | ||
964 | ft_buffer[ft_head]->retry > 0 ? " retry" : ""); | ||
965 | if (ft_buffer[ft_head]->retry > 0) { /* this is a retry */ | ||
966 | int dist = segment_id - last_segment; | ||
967 | |||
968 | if ((int)ft_history.overrun_errors < overrun_count_offset) { | ||
969 | overrun_count_offset = ft_history.overrun_errors; | ||
970 | } else if (dist < 0 || dist > 50) { | ||
971 | overrun_count_offset = ft_history.overrun_errors; | ||
972 | } else if ((ft_history.overrun_errors - | ||
973 | overrun_count_offset) >= 8) { | ||
974 | if (ftape_increase_threshold() >= 0) { | ||
975 | --ft_buffer[ft_head]->retry; | ||
976 | overrun_count_offset = | ||
977 | ft_history.overrun_errors; | ||
978 | TRACE(ft_t_warn, "increased threshold because " | ||
979 | "of excessive overrun errors"); | ||
980 | } else if (!bad_bus_timing && ft_data_rate >= 1000) { | ||
981 | ftape_half_data_rate(); | ||
982 | --ft_buffer[ft_head]->retry; | ||
983 | bad_bus_timing = 1; | ||
984 | overrun_count_offset = | ||
985 | ft_history.overrun_errors; | ||
986 | TRACE(ft_t_warn, "reduced datarate because " | ||
987 | "of excessive overrun errors"); | ||
988 | } | ||
989 | } | ||
990 | } | ||
991 | last_segment = segment_id; | ||
992 | if (ft_location.track != track || | ||
993 | (ftape_might_be_off_track && ft_buffer[ft_head]->retry== 0)) { | ||
994 | /* current track unknown or not equal to destination | ||
995 | */ | ||
996 | ftape_ready_wait(ftape_timeout.seek, &status); | ||
997 | ftape_seek_head_to_track(track); | ||
998 | /* overrun_count_offset = ft_history.overrun_errors; */ | ||
999 | } | ||
1000 | result = -EIO; | ||
1001 | retry = 0; | ||
1002 | while (result < 0 && | ||
1003 | retry++ <= 5 && | ||
1004 | !ft_failure && | ||
1005 | !(sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { | ||
1006 | |||
1007 | if (retry && start_offset < 5) { | ||
1008 | start_offset ++; | ||
1009 | } | ||
1010 | /* Check if we are able to catch the requested | ||
1011 | * segment in time. | ||
1012 | */ | ||
1013 | if ((ft_location.known || (determine_position() == 0)) && | ||
1014 | ft_location.segment >= | ||
1015 | (segment_id - | ||
1016 | ((ftape_tape_running || ft_location.bot) | ||
1017 | ? 0 : start_offset))) { | ||
1018 | /* Too far ahead (in or past target segment). | ||
1019 | */ | ||
1020 | if (ftape_tape_running) { | ||
1021 | if ((result = ftape_stop_tape(&status)) < 0) { | ||
1022 | TRACE(ft_t_err, | ||
1023 | "stop tape failed with code %d", | ||
1024 | result); | ||
1025 | break; | ||
1026 | } | ||
1027 | TRACE(ft_t_noise, "tape stopped"); | ||
1028 | ftape_tape_running = 0; | ||
1029 | } | ||
1030 | TRACE(ft_t_noise, "repositioning"); | ||
1031 | ++ft_history.rewinds; | ||
1032 | if (segment_id % ft_segments_per_track < start_offset){ | ||
1033 | TRACE(ft_t_noise, "end of track condition\n" | ||
1034 | KERN_INFO "segment_id : %d\n" | ||
1035 | KERN_INFO "ft_segments_per_track: %d\n" | ||
1036 | KERN_INFO "start_offset : %d", | ||
1037 | segment_id, ft_segments_per_track, | ||
1038 | start_offset); | ||
1039 | |||
1040 | /* If seeking to first segments on | ||
1041 | * track better do a complete rewind | ||
1042 | * to logical begin of track to get a | ||
1043 | * more steady tape motion. | ||
1044 | */ | ||
1045 | result = ftape_command_wait( | ||
1046 | (ft_location.track & 1) | ||
1047 | ? QIC_PHYSICAL_FORWARD | ||
1048 | : QIC_PHYSICAL_REVERSE, | ||
1049 | ftape_timeout.rewind, &status); | ||
1050 | check_bot_eot(status); /* update location */ | ||
1051 | } else { | ||
1052 | result= skip_reverse(segment_id - start_offset, | ||
1053 | &status); | ||
1054 | } | ||
1055 | } | ||
1056 | if (!ft_location.known) { | ||
1057 | TRACE(ft_t_bug, "panic: location not known"); | ||
1058 | result = -EIO; | ||
1059 | continue; /* while() will check for failure */ | ||
1060 | } | ||
1061 | TRACE(ft_t_noise, "current segment: %d/%d", | ||
1062 | ft_location.segment, ft_location.sector); | ||
1063 | /* We're on the right track somewhere before the | ||
1064 | * wanted segment. Start tape movement if needed and | ||
1065 | * skip to just before or inside the requested | ||
1066 | * segment. Keep tape running. | ||
1067 | */ | ||
1068 | result = 0; | ||
1069 | if (ft_location.segment < | ||
1070 | (segment_id - ((ftape_tape_running || ft_location.bot) | ||
1071 | ? 0 : start_offset))) { | ||
1072 | if (sector_offset > 0) { | ||
1073 | result = seek_forward(segment_id, | ||
1074 | retry <= 3); | ||
1075 | } else { | ||
1076 | result = seek_forward(segment_id - 1, | ||
1077 | retry <= 3); | ||
1078 | } | ||
1079 | } | ||
1080 | if (result == 0 && | ||
1081 | ft_location.segment != | ||
1082 | (segment_id - (sector_offset > 0 ? 0 : 1))) { | ||
1083 | result = -EIO; | ||
1084 | } | ||
1085 | } | ||
1086 | if (result < 0) { | ||
1087 | TRACE(ft_t_err, "failed to reposition"); | ||
1088 | } else { | ||
1089 | ft_runner_status = running; | ||
1090 | } | ||
1091 | TRACE_EXIT result; | ||
1092 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-rw.h b/drivers/char/ftape/lowlevel/ftape-rw.h deleted file mode 100644 index 32f4feeb887c..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-rw.h +++ /dev/null | |||
@@ -1,111 +0,0 @@ | |||
1 | #ifndef _FTAPE_RW_H | ||
2 | #define _FTAPE_RW_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-rw.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:25 $ | ||
26 | * | ||
27 | * This file contains the definitions for the read and write | ||
28 | * functions for the QIC-117 floppy-tape driver for Linux. | ||
29 | * | ||
30 | * Claus-Justus Heine (1996/09/20): Add definition of format code 6 | ||
31 | * Claus-Justus Heine (1996/10/04): Changed GET/PUT macros to cast to (__u8 *) | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | #include "../lowlevel/fdc-io.h" | ||
36 | #include "../lowlevel/ftape-init.h" | ||
37 | #include "../lowlevel/ftape-bsm.h" | ||
38 | |||
39 | #include <asm/unaligned.h> | ||
40 | |||
41 | #define GET2(address, offset) get_unaligned((__u16*)((__u8 *)address + offset)) | ||
42 | #define GET4(address, offset) get_unaligned((__u32*)((__u8 *)address + offset)) | ||
43 | #define GET8(address, offset) get_unaligned((__u64*)((__u8 *)address + offset)) | ||
44 | #define PUT2(address, offset , value) put_unaligned((value), (__u16*)((__u8 *)address + offset)) | ||
45 | #define PUT4(address, offset , value) put_unaligned((value), (__u32*)((__u8 *)address + offset)) | ||
46 | #define PUT8(address, offset , value) put_unaligned((value), (__u64*)((__u8 *)address + offset)) | ||
47 | |||
48 | enum runner_status_enum { | ||
49 | idle = 0, | ||
50 | running, | ||
51 | do_abort, | ||
52 | aborting, | ||
53 | logical_eot, | ||
54 | end_of_tape, | ||
55 | }; | ||
56 | |||
57 | typedef enum ft_buffer_queue { | ||
58 | ft_queue_head = 0, | ||
59 | ft_queue_tail = 1 | ||
60 | } ft_buffer_queue_t; | ||
61 | |||
62 | |||
63 | typedef struct { | ||
64 | int track; /* tape head position */ | ||
65 | volatile int segment; /* current segment */ | ||
66 | volatile int sector; /* sector offset within current segment */ | ||
67 | volatile unsigned int bot; /* logical begin of track */ | ||
68 | volatile unsigned int eot; /* logical end of track */ | ||
69 | volatile unsigned int known; /* validates bot, segment, sector */ | ||
70 | } location_record; | ||
71 | |||
72 | /* Count nr of 1's in pattern. | ||
73 | */ | ||
74 | static inline int count_ones(unsigned long mask) | ||
75 | { | ||
76 | int bits; | ||
77 | |||
78 | for (bits = 0; mask != 0; mask >>= 1) { | ||
79 | if (mask & 1) { | ||
80 | ++bits; | ||
81 | } | ||
82 | } | ||
83 | return bits; | ||
84 | } | ||
85 | |||
86 | #define FT_MAX_NR_BUFFERS 16 /* arbitrary value */ | ||
87 | /* ftape-rw.c defined global vars. | ||
88 | */ | ||
89 | extern buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS]; | ||
90 | extern int ft_nr_buffers; | ||
91 | extern location_record ft_location; | ||
92 | extern volatile int ftape_tape_running; | ||
93 | |||
94 | /* ftape-rw.c defined global functions. | ||
95 | */ | ||
96 | extern int ftape_setup_new_segment(buffer_struct * buff, | ||
97 | int segment_id, | ||
98 | int offset); | ||
99 | extern int ftape_calc_next_cluster(buffer_struct * buff); | ||
100 | extern buffer_struct *ftape_next_buffer (ft_buffer_queue_t pos); | ||
101 | extern buffer_struct *ftape_get_buffer (ft_buffer_queue_t pos); | ||
102 | extern int ftape_buffer_id (ft_buffer_queue_t pos); | ||
103 | extern void ftape_reset_buffer(void); | ||
104 | extern void ftape_tape_parameters(__u8 drive_configuration); | ||
105 | extern int ftape_wait_segment(buffer_state_enum state); | ||
106 | extern int ftape_dumb_stop(void); | ||
107 | extern int ftape_start_tape(int segment_id, int offset); | ||
108 | extern int ftape_stop_tape(int *pstatus); | ||
109 | extern int ftape_handle_logical_eot(void); | ||
110 | extern buffer_state_enum ftape_set_state(buffer_state_enum new_state); | ||
111 | #endif /* _FTAPE_RW_H */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-setup.c b/drivers/char/ftape/lowlevel/ftape-setup.c deleted file mode 100644 index 678340acd0b7..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-setup.c +++ /dev/null | |||
@@ -1,104 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996, 1997 Claus-Justus Heine. | ||
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 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-setup.c,v $ | ||
20 | * $Revision: 1.7 $ | ||
21 | * $Date: 1997/10/10 09:57:06 $ | ||
22 | * | ||
23 | * This file contains the code for processing the kernel command | ||
24 | * line options for the QIC-40/80/3010/3020 floppy-tape driver | ||
25 | * "ftape" for Linux. | ||
26 | */ | ||
27 | |||
28 | #include <linux/string.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/mm.h> | ||
31 | |||
32 | #include <linux/ftape.h> | ||
33 | #include <linux/init.h> | ||
34 | #include "../lowlevel/ftape-tracing.h" | ||
35 | #include "../lowlevel/fdc-io.h" | ||
36 | |||
37 | static struct param_table { | ||
38 | const char *name; | ||
39 | int *var; | ||
40 | int def_param; | ||
41 | int min; | ||
42 | int max; | ||
43 | } config_params[] __initdata = { | ||
44 | #ifndef CONFIG_FT_NO_TRACE_AT_ALL | ||
45 | { "tracing", &ftape_tracing, 3, ft_t_bug, ft_t_any}, | ||
46 | #endif | ||
47 | { "ioport", &ft_fdc_base, CONFIG_FT_FDC_BASE, 0x0, 0xfff}, | ||
48 | { "irq", &ft_fdc_irq, CONFIG_FT_FDC_IRQ, 2, 15}, | ||
49 | { "dma", &ft_fdc_dma, CONFIG_FT_FDC_DMA, 0, 3}, | ||
50 | { "threshold", &ft_fdc_threshold, CONFIG_FT_FDC_THR, 1, 16}, | ||
51 | { "datarate", &ft_fdc_rate_limit, CONFIG_FT_FDC_MAX_RATE, 500, 2000}, | ||
52 | { "fc10", &ft_probe_fc10, CONFIG_FT_PROBE_FC10, 0, 1}, | ||
53 | { "mach2", &ft_mach2, CONFIG_FT_MACH2, 0, 1} | ||
54 | }; | ||
55 | |||
56 | static int __init ftape_setup(char *str) | ||
57 | { | ||
58 | int i; | ||
59 | int param; | ||
60 | int ints[2]; | ||
61 | |||
62 | TRACE_FUN(ft_t_flow); | ||
63 | |||
64 | str = get_options(str, ARRAY_SIZE(ints), ints); | ||
65 | if (str) { | ||
66 | for (i=0; i < NR_ITEMS(config_params); i++) { | ||
67 | if (strcmp(str,config_params[i].name) == 0){ | ||
68 | if (ints[0]) { | ||
69 | param = ints[1]; | ||
70 | } else { | ||
71 | param = config_params[i].def_param; | ||
72 | } | ||
73 | if (param < config_params[i].min || | ||
74 | param > config_params[i].max) { | ||
75 | TRACE(ft_t_err, | ||
76 | "parameter %s out of range %d ... %d", | ||
77 | config_params[i].name, | ||
78 | config_params[i].min, | ||
79 | config_params[i].max); | ||
80 | goto out; | ||
81 | } | ||
82 | if(config_params[i].var) { | ||
83 | TRACE(ft_t_info, "%s=%d", str, param); | ||
84 | *config_params[i].var = param; | ||
85 | } | ||
86 | goto out; | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | if (str) { | ||
91 | TRACE(ft_t_err, "unknown ftape option [%s]", str); | ||
92 | |||
93 | TRACE(ft_t_err, "allowed options are:"); | ||
94 | for (i=0; i < NR_ITEMS(config_params); i++) { | ||
95 | TRACE(ft_t_err, " %s",config_params[i].name); | ||
96 | } | ||
97 | } else { | ||
98 | TRACE(ft_t_err, "botched ftape option"); | ||
99 | } | ||
100 | out: | ||
101 | TRACE_EXIT 1; | ||
102 | } | ||
103 | |||
104 | __setup("ftape=", ftape_setup); | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.c b/drivers/char/ftape/lowlevel/ftape-tracing.c deleted file mode 100644 index 7fdc6567440b..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-tracing.c +++ /dev/null | |||
@@ -1,118 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-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: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-tracing.c,v $ | ||
21 | * $Revision: 1.2 $ | ||
22 | * $Date: 1997/10/05 19:18:27 $ | ||
23 | * | ||
24 | * This file contains the reading code | ||
25 | * for the QIC-117 floppy-tape driver for Linux. | ||
26 | */ | ||
27 | |||
28 | #include <linux/ftape.h> | ||
29 | #include "../lowlevel/ftape-tracing.h" | ||
30 | |||
31 | /* Global vars. | ||
32 | */ | ||
33 | /* tracing | ||
34 | * set it to: to log : | ||
35 | * 0 bugs | ||
36 | * 1 + errors | ||
37 | * 2 + warnings | ||
38 | * 3 + information | ||
39 | * 4 + more information | ||
40 | * 5 + program flow | ||
41 | * 6 + fdc/dma info | ||
42 | * 7 + data flow | ||
43 | * 8 + everything else | ||
44 | */ | ||
45 | ft_trace_t ftape_tracing = ft_t_info; /* Default level: information and up */ | ||
46 | int ftape_function_nest_level; | ||
47 | |||
48 | /* Local vars. | ||
49 | */ | ||
50 | static __u8 trace_id; | ||
51 | static char spacing[] = "* "; | ||
52 | |||
53 | void ftape_trace_call(const char *file, const char *name) | ||
54 | { | ||
55 | char *indent; | ||
56 | |||
57 | /* Since printk seems not to work with "%*s" format | ||
58 | * we'll use this work-around. | ||
59 | */ | ||
60 | if (ftape_function_nest_level < 0) { | ||
61 | printk(KERN_INFO "function nest level (%d) < 0\n", | ||
62 | ftape_function_nest_level); | ||
63 | ftape_function_nest_level = 0; | ||
64 | } | ||
65 | if (ftape_function_nest_level < sizeof(spacing)) { | ||
66 | indent = (spacing + | ||
67 | sizeof(spacing) - 1 - | ||
68 | ftape_function_nest_level); | ||
69 | } else { | ||
70 | indent = spacing; | ||
71 | } | ||
72 | printk(KERN_INFO "[%03d]%s+%s (%s)\n", | ||
73 | (int) trace_id++, indent, file, name); | ||
74 | } | ||
75 | |||
76 | void ftape_trace_exit(const char *file, const char *name) | ||
77 | { | ||
78 | char *indent; | ||
79 | |||
80 | /* Since printk seems not to work with "%*s" format | ||
81 | * we'll use this work-around. | ||
82 | */ | ||
83 | if (ftape_function_nest_level < 0) { | ||
84 | printk(KERN_INFO "function nest level (%d) < 0\n", ftape_function_nest_level); | ||
85 | ftape_function_nest_level = 0; | ||
86 | } | ||
87 | if (ftape_function_nest_level < sizeof(spacing)) { | ||
88 | indent = (spacing + | ||
89 | sizeof(spacing) - 1 - | ||
90 | ftape_function_nest_level); | ||
91 | } else { | ||
92 | indent = spacing; | ||
93 | } | ||
94 | printk(KERN_INFO "[%03d]%s-%s (%s)\n", | ||
95 | (int) trace_id++, indent, file, name); | ||
96 | } | ||
97 | |||
98 | void ftape_trace_log(const char *file, const char *function) | ||
99 | { | ||
100 | char *indent; | ||
101 | |||
102 | /* Since printk seems not to work with "%*s" format | ||
103 | * we'll use this work-around. | ||
104 | */ | ||
105 | if (ftape_function_nest_level < 0) { | ||
106 | printk(KERN_INFO "function nest level (%d) < 0\n", ftape_function_nest_level); | ||
107 | ftape_function_nest_level = 0; | ||
108 | } | ||
109 | if (ftape_function_nest_level < sizeof(spacing)) { | ||
110 | indent = (spacing + | ||
111 | sizeof(spacing) - 1 - | ||
112 | ftape_function_nest_level); | ||
113 | } else { | ||
114 | indent = spacing; | ||
115 | } | ||
116 | printk(KERN_INFO "[%03d]%s%s (%s) - ", | ||
117 | (int) trace_id++, indent, file, function); | ||
118 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.h b/drivers/char/ftape/lowlevel/ftape-tracing.h deleted file mode 100644 index 2950810c7085..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-tracing.h +++ /dev/null | |||
@@ -1,179 +0,0 @@ | |||
1 | #ifndef _FTAPE_TRACING_H | ||
2 | #define _FTAPE_TRACING_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-tracing.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:28 $ | ||
26 | * | ||
27 | * This file contains definitions that eases the debugging of the | ||
28 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
29 | */ | ||
30 | |||
31 | #include <linux/kernel.h> | ||
32 | |||
33 | /* | ||
34 | * Be very careful with TRACE_EXIT and TRACE_ABORT. | ||
35 | * | ||
36 | * if (something) TRACE_EXIT error; | ||
37 | * | ||
38 | * will NOT work. Use | ||
39 | * | ||
40 | * if (something) { | ||
41 | * TRACE_EXIT error; | ||
42 | * } | ||
43 | * | ||
44 | * instead. Maybe a bit dangerous, but save lots of lines of code. | ||
45 | */ | ||
46 | |||
47 | #define LL_X "%d/%d KB" | ||
48 | #define LL(x) (unsigned int)((__u64)(x)>>10), (unsigned int)((x)&1023) | ||
49 | |||
50 | typedef enum { | ||
51 | ft_t_nil = -1, | ||
52 | ft_t_bug, | ||
53 | ft_t_err, | ||
54 | ft_t_warn, | ||
55 | ft_t_info, | ||
56 | ft_t_noise, | ||
57 | ft_t_flow, | ||
58 | ft_t_fdc_dma, | ||
59 | ft_t_data_flow, | ||
60 | ft_t_any | ||
61 | } ft_trace_t; | ||
62 | |||
63 | #ifdef CONFIG_FT_NO_TRACE_AT_ALL | ||
64 | /* the compiler will optimize away most TRACE() macros | ||
65 | */ | ||
66 | #define FT_TRACE_TOP_LEVEL ft_t_bug | ||
67 | #define TRACE_FUN(level) do {} while(0) | ||
68 | #define TRACE_EXIT return | ||
69 | #define TRACE(l, m, i...) \ | ||
70 | { \ | ||
71 | if ((ft_trace_t)(l) == FT_TRACE_TOP_LEVEL) { \ | ||
72 | printk(KERN_INFO"ftape%s(%s):\n" \ | ||
73 | KERN_INFO m".\n" ,__FILE__, __FUNCTION__ , ##i); \ | ||
74 | } \ | ||
75 | } | ||
76 | #define SET_TRACE_LEVEL(l) if ((l) == (l)) do {} while(0) | ||
77 | #define TRACE_LEVEL FT_TRACE_TOP_LEVEL | ||
78 | |||
79 | #else | ||
80 | |||
81 | #ifdef CONFIG_FT_NO_TRACE | ||
82 | /* the compiler will optimize away many TRACE() macros | ||
83 | * the ftape_simple_trace_call() function simply increments | ||
84 | * the function nest level. | ||
85 | */ | ||
86 | #define FT_TRACE_TOP_LEVEL ft_t_warn | ||
87 | #define TRACE_FUN(level) ftape_function_nest_level++ | ||
88 | #define TRACE_EXIT ftape_function_nest_level--; return | ||
89 | |||
90 | #else | ||
91 | #ifdef CONFIG_FT_FULL_DEBUG | ||
92 | #define FT_TRACE_TOP_LEVEL ft_t_any | ||
93 | #else | ||
94 | #define FT_TRACE_TOP_LEVEL ft_t_flow | ||
95 | #endif | ||
96 | #define TRACE_FUN(level) \ | ||
97 | const ft_trace_t _tracing = level; \ | ||
98 | if (ftape_tracing >= (ft_trace_t)(level) && \ | ||
99 | (ft_trace_t)(level) <= FT_TRACE_TOP_LEVEL) \ | ||
100 | ftape_trace_call(__FILE__, __FUNCTION__); \ | ||
101 | ftape_function_nest_level ++; | ||
102 | |||
103 | #define TRACE_EXIT \ | ||
104 | --ftape_function_nest_level; \ | ||
105 | if (ftape_tracing >= (ft_trace_t)(_tracing) && \ | ||
106 | (ft_trace_t)(_tracing) <= FT_TRACE_TOP_LEVEL) \ | ||
107 | ftape_trace_exit(__FILE__, __FUNCTION__); \ | ||
108 | return | ||
109 | |||
110 | #endif | ||
111 | |||
112 | #define TRACE(l, m, i...) \ | ||
113 | { \ | ||
114 | if (ftape_tracing >= (ft_trace_t)(l) && \ | ||
115 | (ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \ | ||
116 | ftape_trace_log(__FILE__, __FUNCTION__); \ | ||
117 | printk(m".\n" ,##i); \ | ||
118 | } \ | ||
119 | } | ||
120 | |||
121 | #define SET_TRACE_LEVEL(l) \ | ||
122 | { \ | ||
123 | if ((ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \ | ||
124 | ftape_tracing = (ft_trace_t)(l); \ | ||
125 | } else { \ | ||
126 | ftape_tracing = FT_TRACE_TOP_LEVEL; \ | ||
127 | } \ | ||
128 | } | ||
129 | #define TRACE_LEVEL \ | ||
130 | ((ftape_tracing <= FT_TRACE_TOP_LEVEL) ? ftape_tracing : FT_TRACE_TOP_LEVEL) | ||
131 | |||
132 | |||
133 | /* Global variables declared in tracing.c | ||
134 | */ | ||
135 | extern ft_trace_t ftape_tracing; /* sets default level */ | ||
136 | extern int ftape_function_nest_level; | ||
137 | |||
138 | /* Global functions declared in tracing.c | ||
139 | */ | ||
140 | extern void ftape_trace_call(const char *file, const char *name); | ||
141 | extern void ftape_trace_exit(const char *file, const char *name); | ||
142 | extern void ftape_trace_log (const char *file, const char *name); | ||
143 | |||
144 | #endif /* !defined(CONFIG_FT_NO_TRACE_AT_ALL) */ | ||
145 | |||
146 | /* | ||
147 | * Abort with a message. | ||
148 | */ | ||
149 | #define TRACE_ABORT(res, i...) \ | ||
150 | { \ | ||
151 | TRACE(i); \ | ||
152 | TRACE_EXIT res; \ | ||
153 | } | ||
154 | |||
155 | /* The following transforms the common "if(result < 0) ... " into a | ||
156 | * one-liner. | ||
157 | */ | ||
158 | #define _TRACE_CATCH(level, fun, action) \ | ||
159 | { \ | ||
160 | int _res = (fun); \ | ||
161 | if (_res < 0) { \ | ||
162 | do { action /* */ ; } while(0); \ | ||
163 | TRACE_ABORT(_res, level, "%s failed: %d", #fun, _res); \ | ||
164 | } \ | ||
165 | } | ||
166 | |||
167 | #define TRACE_CATCH(fun, fail) _TRACE_CATCH(ft_t_err, fun, fail) | ||
168 | |||
169 | /* Abort the current function when signalled. This doesn't belong here, | ||
170 | * but rather into ftape-rw.h (maybe) | ||
171 | */ | ||
172 | #define FT_SIGNAL_EXIT(sig_mask) \ | ||
173 | if (sigtestsetmask(¤t->pending.signal, sig_mask)) { \ | ||
174 | TRACE_ABORT(-EINTR, \ | ||
175 | ft_t_warn, \ | ||
176 | "interrupted by non-blockable signal"); \ | ||
177 | } | ||
178 | |||
179 | #endif /* _FTAPE_TRACING_H */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-write.c b/drivers/char/ftape/lowlevel/ftape-write.c deleted file mode 100644 index 45601ec801ee..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-write.c +++ /dev/null | |||
@@ -1,336 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1995 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: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-write.c,v $ | ||
21 | * $Revision: 1.3.4.1 $ | ||
22 | * $Date: 1997/11/14 18:07:04 $ | ||
23 | * | ||
24 | * This file contains the writing code | ||
25 | * for the QIC-117 floppy-tape driver for Linux. | ||
26 | */ | ||
27 | |||
28 | #include <linux/string.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/mm.h> | ||
31 | |||
32 | #include <linux/ftape.h> | ||
33 | #include <linux/qic117.h> | ||
34 | #include "../lowlevel/ftape-tracing.h" | ||
35 | #include "../lowlevel/ftape-write.h" | ||
36 | #include "../lowlevel/ftape-read.h" | ||
37 | #include "../lowlevel/ftape-io.h" | ||
38 | #include "../lowlevel/ftape-ctl.h" | ||
39 | #include "../lowlevel/ftape-rw.h" | ||
40 | #include "../lowlevel/ftape-ecc.h" | ||
41 | #include "../lowlevel/ftape-bsm.h" | ||
42 | #include "../lowlevel/fdc-isr.h" | ||
43 | |||
44 | /* Global vars. | ||
45 | */ | ||
46 | |||
47 | /* Local vars. | ||
48 | */ | ||
49 | static int last_write_failed; | ||
50 | |||
51 | void ftape_zap_write_buffers(void) | ||
52 | { | ||
53 | int i; | ||
54 | |||
55 | for (i = 0; i < ft_nr_buffers; ++i) { | ||
56 | ft_buffer[i]->status = done; | ||
57 | } | ||
58 | ftape_reset_buffer(); | ||
59 | } | ||
60 | |||
61 | static int copy_and_gen_ecc(void *destination, | ||
62 | const void *source, | ||
63 | const SectorMap bad_sector_map) | ||
64 | { | ||
65 | int result; | ||
66 | struct memory_segment mseg; | ||
67 | int bads = count_ones(bad_sector_map); | ||
68 | TRACE_FUN(ft_t_any); | ||
69 | |||
70 | if (bads > 0) { | ||
71 | TRACE(ft_t_noise, "bad sectors in map: %d", bads); | ||
72 | } | ||
73 | if (bads + 3 >= FT_SECTORS_PER_SEGMENT) { | ||
74 | TRACE(ft_t_noise, "empty segment"); | ||
75 | mseg.blocks = 0; /* skip entire segment */ | ||
76 | result = 0; /* nothing written */ | ||
77 | } else { | ||
78 | mseg.blocks = FT_SECTORS_PER_SEGMENT - bads; | ||
79 | mseg.data = destination; | ||
80 | memcpy(mseg.data, source, (mseg.blocks - 3) * FT_SECTOR_SIZE); | ||
81 | result = ftape_ecc_set_segment_parity(&mseg); | ||
82 | if (result < 0) { | ||
83 | TRACE(ft_t_err, "ecc_set_segment_parity failed"); | ||
84 | } else { | ||
85 | result = (mseg.blocks - 3) * FT_SECTOR_SIZE; | ||
86 | } | ||
87 | } | ||
88 | TRACE_EXIT result; | ||
89 | } | ||
90 | |||
91 | |||
92 | int ftape_start_writing(const ft_write_mode_t mode) | ||
93 | { | ||
94 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
95 | int segment_id = head->segment_id; | ||
96 | int result; | ||
97 | buffer_state_enum wanted_state = (mode == FT_WR_DELETE | ||
98 | ? deleting | ||
99 | : writing); | ||
100 | TRACE_FUN(ft_t_flow); | ||
101 | |||
102 | if ((ft_driver_state != wanted_state) || head->status != waiting) { | ||
103 | TRACE_EXIT 0; | ||
104 | } | ||
105 | ftape_setup_new_segment(head, segment_id, 1); | ||
106 | if (mode == FT_WR_SINGLE) { | ||
107 | /* stop tape instead of pause */ | ||
108 | head->next_segment = 0; | ||
109 | } | ||
110 | ftape_calc_next_cluster(head); /* prepare */ | ||
111 | head->status = ft_driver_state; /* either writing or deleting */ | ||
112 | if (ft_runner_status == idle) { | ||
113 | TRACE(ft_t_noise, | ||
114 | "starting runner for segment %d", segment_id); | ||
115 | TRACE_CATCH(ftape_start_tape(segment_id,head->sector_offset),); | ||
116 | } else { | ||
117 | TRACE(ft_t_noise, "runner not idle, not starting tape"); | ||
118 | } | ||
119 | /* go */ | ||
120 | result = fdc_setup_read_write(head, (mode == FT_WR_DELETE | ||
121 | ? FDC_WRITE_DELETED : FDC_WRITE)); | ||
122 | ftape_set_state(wanted_state); /* should not be necessary */ | ||
123 | TRACE_EXIT result; | ||
124 | } | ||
125 | |||
126 | /* Wait until all data is actually written to tape. | ||
127 | * | ||
128 | * There is a problem: when the tape runs into logical EOT, then this | ||
129 | * failes. We need to restart the runner in this case. | ||
130 | */ | ||
131 | int ftape_loop_until_writes_done(void) | ||
132 | { | ||
133 | buffer_struct *head; | ||
134 | TRACE_FUN(ft_t_flow); | ||
135 | |||
136 | while ((ft_driver_state == writing || ft_driver_state == deleting) && | ||
137 | ftape_get_buffer(ft_queue_head)->status != done) { | ||
138 | /* set the runner status to idle if at lEOT */ | ||
139 | TRACE_CATCH(ftape_handle_logical_eot(), last_write_failed = 1); | ||
140 | /* restart the tape if necessary */ | ||
141 | if (ft_runner_status == idle) { | ||
142 | TRACE(ft_t_noise, "runner is idle, restarting"); | ||
143 | if (ft_driver_state == deleting) { | ||
144 | TRACE_CATCH(ftape_start_writing(FT_WR_DELETE), | ||
145 | last_write_failed = 1); | ||
146 | } else { | ||
147 | TRACE_CATCH(ftape_start_writing(FT_WR_MULTI), | ||
148 | last_write_failed = 1); | ||
149 | } | ||
150 | } | ||
151 | TRACE(ft_t_noise, "tail: %d, head: %d", | ||
152 | ftape_buffer_id(ft_queue_tail), | ||
153 | ftape_buffer_id(ft_queue_head)); | ||
154 | TRACE_CATCH(fdc_interrupt_wait(5 * FT_SECOND), | ||
155 | last_write_failed = 1); | ||
156 | head = ftape_get_buffer(ft_queue_head); | ||
157 | if (head->status == error) { | ||
158 | /* Allow escape from loop when signaled ! | ||
159 | */ | ||
160 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
161 | if (head->hard_error_map != 0) { | ||
162 | /* Implement hard write error recovery here | ||
163 | */ | ||
164 | } | ||
165 | /* retry this one */ | ||
166 | head->status = waiting; | ||
167 | if (ft_runner_status == aborting) { | ||
168 | ftape_dumb_stop(); | ||
169 | } | ||
170 | if (ft_runner_status != idle) { | ||
171 | TRACE_ABORT(-EIO, ft_t_err, | ||
172 | "unexpected state: " | ||
173 | "ft_runner_status != idle"); | ||
174 | } | ||
175 | ftape_start_writing(ft_driver_state == deleting | ||
176 | ? FT_WR_MULTI : FT_WR_DELETE); | ||
177 | } | ||
178 | TRACE(ft_t_noise, "looping until writes done"); | ||
179 | } | ||
180 | ftape_set_state(idle); | ||
181 | TRACE_EXIT 0; | ||
182 | } | ||
183 | |||
184 | /* Write given segment from buffer at address to tape. | ||
185 | */ | ||
186 | static int write_segment(const int segment_id, | ||
187 | const void *address, | ||
188 | const ft_write_mode_t write_mode) | ||
189 | { | ||
190 | int bytes_written = 0; | ||
191 | buffer_struct *tail; | ||
192 | buffer_state_enum wanted_state = (write_mode == FT_WR_DELETE | ||
193 | ? deleting : writing); | ||
194 | TRACE_FUN(ft_t_flow); | ||
195 | |||
196 | TRACE(ft_t_noise, "segment_id = %d", segment_id); | ||
197 | if (ft_driver_state != wanted_state) { | ||
198 | if (ft_driver_state == deleting || | ||
199 | wanted_state == deleting) { | ||
200 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
201 | } | ||
202 | TRACE(ft_t_noise, "calling ftape_abort_operation"); | ||
203 | TRACE_CATCH(ftape_abort_operation(),); | ||
204 | ftape_zap_write_buffers(); | ||
205 | ftape_set_state(wanted_state); | ||
206 | } | ||
207 | /* if all buffers full we'll have to wait... | ||
208 | */ | ||
209 | ftape_wait_segment(wanted_state); | ||
210 | tail = ftape_get_buffer(ft_queue_tail); | ||
211 | switch(tail->status) { | ||
212 | case done: | ||
213 | ft_history.defects += count_ones(tail->hard_error_map); | ||
214 | break; | ||
215 | case waiting: | ||
216 | /* this could happen with multiple EMPTY_SEGMENTs, but | ||
217 | * shouldn't happen any more as we re-start the runner even | ||
218 | * with an empty segment. | ||
219 | */ | ||
220 | bytes_written = -EAGAIN; | ||
221 | break; | ||
222 | case error: | ||
223 | /* setup for a retry | ||
224 | */ | ||
225 | tail->status = waiting; | ||
226 | bytes_written = -EAGAIN; /* force retry */ | ||
227 | if (tail->hard_error_map != 0) { | ||
228 | TRACE(ft_t_warn, | ||
229 | "warning: %d hard error(s) in written segment", | ||
230 | count_ones(tail->hard_error_map)); | ||
231 | TRACE(ft_t_noise, "hard_error_map = 0x%08lx", | ||
232 | (long)tail->hard_error_map); | ||
233 | /* Implement hard write error recovery here | ||
234 | */ | ||
235 | } | ||
236 | break; | ||
237 | default: | ||
238 | TRACE_ABORT(-EIO, ft_t_err, | ||
239 | "wait for empty segment failed, tail status: %d", | ||
240 | tail->status); | ||
241 | } | ||
242 | /* should runner stop ? | ||
243 | */ | ||
244 | if (ft_runner_status == aborting) { | ||
245 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
246 | if (head->status == wanted_state) { | ||
247 | head->status = done; /* ???? */ | ||
248 | } | ||
249 | /* don't call abort_operation(), we don't want to zap | ||
250 | * the dma buffers | ||
251 | */ | ||
252 | TRACE_CATCH(ftape_dumb_stop(),); | ||
253 | } else { | ||
254 | /* If just passed last segment on tape: wait for BOT | ||
255 | * or EOT mark. Sets ft_runner_status to idle if at lEOT | ||
256 | * and successful | ||
257 | */ | ||
258 | TRACE_CATCH(ftape_handle_logical_eot(),); | ||
259 | } | ||
260 | if (tail->status == done) { | ||
261 | /* now at least one buffer is empty, fill it with our | ||
262 | * data. skip bad sectors and generate ecc. | ||
263 | * copy_and_gen_ecc return nr of bytes written, range | ||
264 | * 0..29 Kb inclusive! | ||
265 | * | ||
266 | * Empty segments are handled inside coyp_and_gen_ecc() | ||
267 | */ | ||
268 | if (write_mode != FT_WR_DELETE) { | ||
269 | TRACE_CATCH(bytes_written = copy_and_gen_ecc( | ||
270 | tail->address, address, | ||
271 | ftape_get_bad_sector_entry(segment_id)),); | ||
272 | } | ||
273 | tail->segment_id = segment_id; | ||
274 | tail->status = waiting; | ||
275 | tail = ftape_next_buffer(ft_queue_tail); | ||
276 | } | ||
277 | /* Start tape only if all buffers full or flush mode. | ||
278 | * This will give higher probability of streaming. | ||
279 | */ | ||
280 | if (ft_runner_status != running && | ||
281 | ((tail->status == waiting && | ||
282 | ftape_get_buffer(ft_queue_head) == tail) || | ||
283 | write_mode != FT_WR_ASYNC)) { | ||
284 | TRACE_CATCH(ftape_start_writing(write_mode),); | ||
285 | } | ||
286 | TRACE_EXIT bytes_written; | ||
287 | } | ||
288 | |||
289 | /* Write as much as fits from buffer to the given segment on tape | ||
290 | * and handle retries. | ||
291 | * Return the number of bytes written (>= 0), or: | ||
292 | * -EIO write failed | ||
293 | * -EINTR interrupted by signal | ||
294 | * -ENOSPC device full | ||
295 | */ | ||
296 | int ftape_write_segment(const int segment_id, | ||
297 | const void *buffer, | ||
298 | const ft_write_mode_t flush) | ||
299 | { | ||
300 | int retry = 0; | ||
301 | int result; | ||
302 | TRACE_FUN(ft_t_flow); | ||
303 | |||
304 | ft_history.used |= 2; | ||
305 | if (segment_id >= ft_tracks_per_tape*ft_segments_per_track) { | ||
306 | /* tape full */ | ||
307 | TRACE_ABORT(-ENOSPC, ft_t_err, | ||
308 | "invalid segment id: %d (max %d)", | ||
309 | segment_id, | ||
310 | ft_tracks_per_tape * ft_segments_per_track -1); | ||
311 | } | ||
312 | for (;;) { | ||
313 | if ((result = write_segment(segment_id, buffer, flush)) >= 0) { | ||
314 | if (result == 0) { /* empty segment */ | ||
315 | TRACE(ft_t_noise, | ||
316 | "empty segment, nothing written"); | ||
317 | } | ||
318 | TRACE_EXIT result; | ||
319 | } | ||
320 | if (result == -EAGAIN) { | ||
321 | if (++retry > 100) { /* give up */ | ||
322 | TRACE_ABORT(-EIO, ft_t_err, | ||
323 | "write failed, >100 retries in segment"); | ||
324 | } | ||
325 | TRACE(ft_t_warn, "write error, retry %d (%d)", | ||
326 | retry, | ||
327 | ftape_get_buffer(ft_queue_tail)->segment_id); | ||
328 | } else { | ||
329 | TRACE_ABORT(result, ft_t_err, | ||
330 | "write_segment failed, error: %d", result); | ||
331 | } | ||
332 | /* Allow escape from loop when signaled ! | ||
333 | */ | ||
334 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
335 | } | ||
336 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-write.h b/drivers/char/ftape/lowlevel/ftape-write.h deleted file mode 100644 index 0e7f898b7af9..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-write.h +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | #ifndef _FTAPE_WRITE_H | ||
2 | #define _FTAPE_WRITE_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1995 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-write.h,v $ | ||
24 | $Author: claus $ | ||
25 | * | ||
26 | $Revision: 1.2 $ | ||
27 | $Date: 1997/10/05 19:18:30 $ | ||
28 | $State: Exp $ | ||
29 | * | ||
30 | * This file contains the definitions for the write functions | ||
31 | * for the QIC-117 floppy-tape driver for Linux. | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | |||
36 | /* ftape-write.c defined global functions. | ||
37 | */ | ||
38 | typedef enum { | ||
39 | FT_WR_ASYNC = 0, /* start tape only when all buffers are full */ | ||
40 | FT_WR_MULTI = 1, /* start tape, but don't necessarily stop */ | ||
41 | FT_WR_SINGLE = 2, /* write a single segment and stop afterwards */ | ||
42 | FT_WR_DELETE = 3 /* write deleted data marks */ | ||
43 | } ft_write_mode_t; | ||
44 | |||
45 | extern int ftape_start_writing(const ft_write_mode_t mode); | ||
46 | extern int ftape_write_segment(const int segment, | ||
47 | const void *address, | ||
48 | const ft_write_mode_t flushing); | ||
49 | extern void ftape_zap_write_buffers(void); | ||
50 | extern int ftape_loop_until_writes_done(void); | ||
51 | |||
52 | #endif /* _FTAPE_WRITE_H */ | ||
53 | |||
diff --git a/drivers/char/ftape/lowlevel/ftape_syms.c b/drivers/char/ftape/lowlevel/ftape_syms.c deleted file mode 100644 index 8e0dc4a07ca6..000000000000 --- a/drivers/char/ftape/lowlevel/ftape_syms.c +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996-1997 Claus-Justus Heine | ||
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 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape_syms.c,v $ | ||
20 | * $Revision: 1.4 $ | ||
21 | * $Date: 1997/10/17 00:03:51 $ | ||
22 | * | ||
23 | * This file contains the symbols that the ftape low level | ||
24 | * part of the QIC-40/80/3010/3020 floppy-tape driver "ftape" | ||
25 | * exports to its high level clients | ||
26 | */ | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | |||
30 | #include <linux/ftape.h> | ||
31 | #include "../lowlevel/ftape-tracing.h" | ||
32 | #include "../lowlevel/ftape-init.h" | ||
33 | #include "../lowlevel/fdc-io.h" | ||
34 | #include "../lowlevel/ftape-read.h" | ||
35 | #include "../lowlevel/ftape-write.h" | ||
36 | #include "../lowlevel/ftape-io.h" | ||
37 | #include "../lowlevel/ftape-ctl.h" | ||
38 | #include "../lowlevel/ftape-rw.h" | ||
39 | #include "../lowlevel/ftape-bsm.h" | ||
40 | #include "../lowlevel/ftape-buffer.h" | ||
41 | #include "../lowlevel/ftape-format.h" | ||
42 | |||
43 | /* bad sector handling from ftape-bsm.c */ | ||
44 | EXPORT_SYMBOL(ftape_get_bad_sector_entry); | ||
45 | EXPORT_SYMBOL(ftape_find_end_of_bsm_list); | ||
46 | /* from ftape-rw.c */ | ||
47 | EXPORT_SYMBOL(ftape_set_state); | ||
48 | /* from ftape-ctl.c */ | ||
49 | EXPORT_SYMBOL(ftape_seek_to_bot); | ||
50 | EXPORT_SYMBOL(ftape_seek_to_eot); | ||
51 | EXPORT_SYMBOL(ftape_abort_operation); | ||
52 | EXPORT_SYMBOL(ftape_get_status); | ||
53 | EXPORT_SYMBOL(ftape_enable); | ||
54 | EXPORT_SYMBOL(ftape_disable); | ||
55 | EXPORT_SYMBOL(ftape_mmap); | ||
56 | EXPORT_SYMBOL(ftape_calibrate_data_rate); | ||
57 | /* from ftape-io.c */ | ||
58 | EXPORT_SYMBOL(ftape_reset_drive); | ||
59 | EXPORT_SYMBOL(ftape_command); | ||
60 | EXPORT_SYMBOL(ftape_parameter); | ||
61 | EXPORT_SYMBOL(ftape_ready_wait); | ||
62 | EXPORT_SYMBOL(ftape_report_operation); | ||
63 | EXPORT_SYMBOL(ftape_report_error); | ||
64 | /* from ftape-read.c */ | ||
65 | EXPORT_SYMBOL(ftape_read_segment_fraction); | ||
66 | EXPORT_SYMBOL(ftape_zap_read_buffers); | ||
67 | EXPORT_SYMBOL(ftape_read_header_segment); | ||
68 | EXPORT_SYMBOL(ftape_decode_header_segment); | ||
69 | /* from ftape-write.c */ | ||
70 | EXPORT_SYMBOL(ftape_write_segment); | ||
71 | EXPORT_SYMBOL(ftape_start_writing); | ||
72 | EXPORT_SYMBOL(ftape_loop_until_writes_done); | ||
73 | /* from ftape-buffer.h */ | ||
74 | EXPORT_SYMBOL(ftape_set_nr_buffers); | ||
75 | /* from ftape-format.h */ | ||
76 | EXPORT_SYMBOL(ftape_format_track); | ||
77 | EXPORT_SYMBOL(ftape_format_status); | ||
78 | EXPORT_SYMBOL(ftape_verify_segment); | ||
79 | /* from tracing.c */ | ||
80 | #ifndef CONFIG_FT_NO_TRACE_AT_ALL | ||
81 | EXPORT_SYMBOL(ftape_tracing); | ||
82 | EXPORT_SYMBOL(ftape_function_nest_level); | ||
83 | EXPORT_SYMBOL(ftape_trace_call); | ||
84 | EXPORT_SYMBOL(ftape_trace_exit); | ||
85 | EXPORT_SYMBOL(ftape_trace_log); | ||
86 | #endif | ||
87 | |||