diff options
150 files changed, 1464 insertions, 21211 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 02457ec9c94f..f08ca9535733 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX | |||
@@ -104,8 +104,6 @@ firmware_class/ | |||
104 | - request_firmware() hotplug interface info. | 104 | - request_firmware() hotplug interface info. |
105 | floppy.txt | 105 | floppy.txt |
106 | - notes and driver options for the floppy disk driver. | 106 | - notes and driver options for the floppy disk driver. |
107 | ftape.txt | ||
108 | - notes about the floppy tape device driver. | ||
109 | hayes-esp.txt | 107 | hayes-esp.txt |
110 | - info on using the Hayes ESP serial driver. | 108 | - info on using the Hayes ESP serial driver. |
111 | highuid.txt | 109 | highuid.txt |
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f81819364b7a..226ecf2ffd56 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -234,14 +234,6 @@ Who: Jean Delvare <khali@linux-fr.org> | |||
234 | 234 | ||
235 | --------------------------- | 235 | --------------------------- |
236 | 236 | ||
237 | What: ftape | ||
238 | When: 2.6.20 | ||
239 | Why: Orphaned for ages. SMP bugs long unfixed. Few users left | ||
240 | in the world. | ||
241 | Who: Jeff Garzik <jeff@garzik.org> | ||
242 | |||
243 | --------------------------- | ||
244 | |||
245 | What: IPv4 only connection tracking/NAT/helpers | 237 | What: IPv4 only connection tracking/NAT/helpers |
246 | When: 2.6.22 | 238 | When: 2.6.22 |
247 | Why: The new layer 3 independant connection tracking replaces the old | 239 | Why: The new layer 3 independant connection tracking replaces the old |
diff --git a/Documentation/ftape.txt b/Documentation/ftape.txt deleted file mode 100644 index 7d8bb3384031..000000000000 --- a/Documentation/ftape.txt +++ /dev/null | |||
@@ -1,307 +0,0 @@ | |||
1 | Intro | ||
2 | ===== | ||
3 | |||
4 | This file describes some issues involved when using the "ftape" | ||
5 | floppy tape device driver that comes with the Linux kernel. | ||
6 | |||
7 | ftape has a home page at | ||
8 | |||
9 | http://ftape.dot-heine.de/ | ||
10 | |||
11 | which contains further information about ftape. Please cross check | ||
12 | this WWW address against the address given (if any) in the MAINTAINERS | ||
13 | file located in the top level directory of the Linux kernel source | ||
14 | tree. | ||
15 | |||
16 | NOTE: This is an unmaintained set of drivers, and it is not guaranteed to work. | ||
17 | If you are interested in taking over maintenance, contact Claus-Justus Heine | ||
18 | <ch@dot-heine.de>, the former maintainer. | ||
19 | |||
20 | Contents | ||
21 | ======== | ||
22 | |||
23 | A minus 1: Ftape documentation | ||
24 | |||
25 | A. Changes | ||
26 | 1. Goal | ||
27 | 2. I/O Block Size | ||
28 | 3. Write Access when not at EOD (End Of Data) or BOT (Begin Of Tape) | ||
29 | 4. Formatting | ||
30 | 5. Interchanging cartridges with other operating systems | ||
31 | |||
32 | B. Debugging Output | ||
33 | 1. Introduction | ||
34 | 2. Tuning the debugging output | ||
35 | |||
36 | C. Boot and load time configuration | ||
37 | 1. Setting boot time parameters | ||
38 | 2. Module load time parameters | ||
39 | 3. Ftape boot- and load time options | ||
40 | 4. Example kernel parameter setting | ||
41 | 5. Example module parameter setting | ||
42 | |||
43 | D. Support and contacts | ||
44 | |||
45 | ******************************************************************************* | ||
46 | |||
47 | A minus 1. Ftape documentation | ||
48 | ============================== | ||
49 | |||
50 | Unluckily, the ftape-HOWTO is out of date. This really needs to be | ||
51 | changed. Up to date documentation as well as recent development | ||
52 | versions of ftape and useful links to related topics can be found at | ||
53 | the ftape home page at | ||
54 | |||
55 | http://ftape.dot-heine.de/ | ||
56 | |||
57 | ******************************************************************************* | ||
58 | |||
59 | A. Changes | ||
60 | ========== | ||
61 | |||
62 | 1. Goal | ||
63 | ~~~~ | ||
64 | The goal of all that incompatibilities was to give ftape an interface | ||
65 | that resembles the interface provided by SCSI tape drives as close | ||
66 | as possible. Thus any Unix backup program that is known to work | ||
67 | with SCSI tape drives should also work. | ||
68 | |||
69 | The concept of a fixed block size for read/write transfers is | ||
70 | rather unrelated to this SCSI tape compatibility at the file system | ||
71 | interface level. It developed out of a feature of zftape, a | ||
72 | block wise user transparent on-the-fly compression. That compression | ||
73 | support will not be dropped in future releases for compatibility | ||
74 | reasons with previous releases of zftape. | ||
75 | |||
76 | 2. I/O Block Size | ||
77 | ~~~~~~~~~~~~~~ | ||
78 | The block size defaults to 10k which is the default block size of | ||
79 | GNU tar. | ||
80 | |||
81 | The block size can be tuned either during kernel configuration or | ||
82 | at runtime with the MTIOCTOP ioctl using the MTSETBLK operation | ||
83 | (i.e. do "mt -f /dev/qft0" setblk #BLKSZ). A block size of 0 | ||
84 | switches to variable block size mode i.e. "mt setblk 0" switches | ||
85 | off the block size restriction. However, this disables zftape's | ||
86 | built in on-the-fly compression which doesn't work with variable | ||
87 | block size mode. | ||
88 | |||
89 | The BLKSZ parameter must be given as a byte count and must be a | ||
90 | multiple of 32k or 0, i.e. use "mt setblk 32768" to switch to a | ||
91 | block size of 32k. | ||
92 | |||
93 | The typical symptom of a block size mismatch is an "invalid | ||
94 | argument" error message. | ||
95 | |||
96 | 3. Write Access when not at EOD (End Of Data) or BOT (Begin Of Tape) | ||
97 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
98 | zftape (the file system interface of ftape-3.x) denies write access | ||
99 | to the tape cartridge when it isn't positioned either at BOT or | ||
100 | EOD. | ||
101 | |||
102 | 4. Formatting | ||
103 | ~~~~~~~~~~ | ||
104 | ftape DOES support formatting of floppy tape cartridges. You need the | ||
105 | `ftformat' program that is shipped with the modules version of ftape. | ||
106 | Please get the latest version of ftape from | ||
107 | |||
108 | ftp://sunsite.unc.edu/pub/Linux/kernel/tapes | ||
109 | |||
110 | or from the ftape home page at | ||
111 | |||
112 | http://ftape.dot-heine.de/ | ||
113 | |||
114 | `ftformat' is contained in the `./contrib/' subdirectory of that | ||
115 | separate ftape package. | ||
116 | |||
117 | 5. Interchanging cartridges with other operating systems | ||
118 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
119 | |||
120 | The internal emulation of Unix tape device file marks has changed | ||
121 | completely. ftape now uses the volume table segment as specified | ||
122 | by the QIC-40/80/3010/3020/113 standards to emulate file marks. As | ||
123 | a consequence there is limited support to interchange cartridges | ||
124 | with other operating systems. | ||
125 | |||
126 | To be more precise: ftape will detect volumes written by other OS's | ||
127 | programs and other OS's programs will detect volumes written by | ||
128 | ftape. | ||
129 | |||
130 | However, it isn't possible to extract the data dumped to the tape | ||
131 | by some MSDOS program with ftape. This exceeds the scope of a | ||
132 | kernel device driver. If you need such functionality, then go ahead | ||
133 | and write a user space utility that is able to do that. ftape already | ||
134 | provides all kernel level support necessary to do that. | ||
135 | |||
136 | ******************************************************************************* | ||
137 | |||
138 | B. Debugging Output | ||
139 | ================ | ||
140 | |||
141 | 1. Introduction | ||
142 | ~~~~~~~~~~~~ | ||
143 | The ftape driver can be very noisy in that is can print lots of | ||
144 | debugging messages to the kernel log files and the system console. | ||
145 | While this is useful for debugging it might be annoying during | ||
146 | normal use and enlarges the size of the driver by several kilobytes. | ||
147 | |||
148 | To reduce the size of the driver you can trim the maximal amount of | ||
149 | debugging information available during kernel configuration. Please | ||
150 | refer to the kernel configuration script and its on-line help | ||
151 | functionality. | ||
152 | |||
153 | The amount of debugging output maps to the "tracing" boot time | ||
154 | option and the "ft_tracing" modules option as follows: | ||
155 | |||
156 | 0 bugs | ||
157 | 1 + errors (with call-stack dump) | ||
158 | 2 + warnings | ||
159 | 3 + information | ||
160 | 4 + more information | ||
161 | 5 + program flow | ||
162 | 6 + fdc/dma info | ||
163 | 7 + data flow | ||
164 | 8 + everything else | ||
165 | |||
166 | 2. Tuning the debugging output | ||
167 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
168 | To reduce the amount of debugging output printed to the system | ||
169 | console you can | ||
170 | |||
171 | i) trim the debugging output at run-time with | ||
172 | |||
173 | mt -f /dev/nqft0 setdensity #DBGLVL | ||
174 | |||
175 | where "#DBGLVL" is a number between 0 and 9 | ||
176 | |||
177 | ii) trim the debugging output at module load time with | ||
178 | |||
179 | modprobe ftape ft_tracing=#DBGLVL | ||
180 | |||
181 | Of course, this applies only if you have configured ftape to be | ||
182 | compiled as a module. | ||
183 | |||
184 | iii) trim the debugging output during system boot time. Add the | ||
185 | following to the kernel command line: | ||
186 | |||
187 | ftape=#DBGLVL,tracing | ||
188 | |||
189 | Please refer also to the next section if you don't know how to | ||
190 | set boot time parameters. | ||
191 | |||
192 | ******************************************************************************* | ||
193 | |||
194 | C. Boot and load time configuration | ||
195 | ================================ | ||
196 | |||
197 | 1. Setting boot time parameters | ||
198 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
199 | Assuming that you use lilo, the LI)nux LO)ader, boot time kernel | ||
200 | parameters can be set by adding a line | ||
201 | |||
202 | append some_kernel_boot_time_parameter | ||
203 | |||
204 | to `/etc/lilo.conf' or at real boot time by typing in the options | ||
205 | at the prompt provided by LILO. I can't give you advice on how to | ||
206 | specify those parameters with other loaders as I don't use them. | ||
207 | |||
208 | For ftape, each "some_kernel_boot_time_parameter" looks like | ||
209 | "ftape=value,option". As an example, the debugging output can be | ||
210 | increased with | ||
211 | |||
212 | ftape=4,tracing | ||
213 | |||
214 | NOTE: the value precedes the option name. | ||
215 | |||
216 | 2. Module load time parameters | ||
217 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
218 | Module parameters can be specified either directly when invoking | ||
219 | the program 'modprobe' at the shell prompt: | ||
220 | |||
221 | modprobe ftape ft_tracing=4 | ||
222 | |||
223 | or by editing the file `/etc/modprobe.conf' in which case they take | ||
224 | effect each time when the module is loaded with `modprobe' (please | ||
225 | refer to the respective manual pages). Thus, you should add a line | ||
226 | |||
227 | options ftape ft_tracing=4 | ||
228 | |||
229 | to `/etc/modprobe.conf` if you intend to increase the debugging | ||
230 | output of the driver. | ||
231 | |||
232 | |||
233 | 3. Ftape boot- and load time options | ||
234 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
235 | |||
236 | i. Controlling the amount of debugging output | ||
237 | DBGLVL has to be replaced by a number between 0 and 8. | ||
238 | |||
239 | module | kernel command line | ||
240 | -----------------------|---------------------- | ||
241 | ft_tracing=DBGLVL | ftape=DBGLVL,tracing | ||
242 | |||
243 | ii. Hardware setup | ||
244 | BASE is the base address of your floppy disk controller, | ||
245 | IRQ and DMA give its interrupt and DMA channel, respectively. | ||
246 | BOOL is an integer, "0" means "no"; any other value means | ||
247 | "yes". You don't need to specify anything if connecting your tape | ||
248 | drive to the standard floppy disk controller. All of these | ||
249 | values have reasonable defaults. The defaults can be modified | ||
250 | during kernel configuration, i.e. while running "make config", | ||
251 | "make menuconfig" or "make xconfig" in the top level directory | ||
252 | of the Linux kernel source tree. Please refer also to the on | ||
253 | line documentation provided during that kernel configuration | ||
254 | process. | ||
255 | |||
256 | ft_probe_fc10 is set to a non-zero value if you wish for ftape to | ||
257 | probe for a Colorado FC-10 or FC-20 controller. | ||
258 | |||
259 | ft_mach2 is set to a non-zero value if you wish for ftape to probe | ||
260 | for a Mountain MACH-2 controller. | ||
261 | |||
262 | module | kernel command line | ||
263 | -----------------------|---------------------- | ||
264 | ft_fdc_base=BASE | ftape=BASE,ioport | ||
265 | ft_fdc_irq=IRQ | ftape=IRQ,irq | ||
266 | ft_fdc_dma=DMA | ftape=DMA,dma | ||
267 | ft_probe_fc10=BOOL | ftape=BOOL,fc10 | ||
268 | ft_mach2=BOOL | ftape=BOOL,mach2 | ||
269 | ft_fdc_threshold=THR | ftape=THR,threshold | ||
270 | ft_fdc_rate_limit=RATE | ftape=RATE,datarate | ||
271 | |||
272 | 4. Example kernel parameter setting | ||
273 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
274 | To configure ftape to probe for a Colorado FC-10/FC-20 controller | ||
275 | and to increase the amount of debugging output a little bit, add | ||
276 | the following line to `/etc/lilo.conf': | ||
277 | |||
278 | append ftape=1,fc10 ftape=4,tracing | ||
279 | |||
280 | 5. Example module parameter setting | ||
281 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
282 | To do the same, but with ftape compiled as a loadable kernel | ||
283 | module, add the following line to `/etc/modprobe.conf': | ||
284 | |||
285 | options ftape ft_probe_fc10=1 ft_tracing=4 | ||
286 | |||
287 | ******************************************************************************* | ||
288 | |||
289 | D. Support and contacts | ||
290 | ==================== | ||
291 | |||
292 | Ftape is distributed under the GNU General Public License. There is | ||
293 | absolutely no warranty for this software. However, you can reach | ||
294 | the current maintainer of the ftape package under the email address | ||
295 | given in the MAINTAINERS file which is located in the top level | ||
296 | directory of the Linux kernel source tree. There you'll find also | ||
297 | the relevant mailing list to use as a discussion forum and the web | ||
298 | page to query for the most recent documentation, related work and | ||
299 | development versions of ftape. | ||
300 | |||
301 | Changelog: | ||
302 | ========== | ||
303 | |||
304 | ~1996: Original Document | ||
305 | |||
306 | 10-24-2004: General cleanup and updating, noting additional module options. | ||
307 | James Nelson <james4765@gmail.com> | ||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 67473849f20e..15e4fed127f6 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -557,9 +557,6 @@ and is between 256 and 4096 characters. It is defined in the file | |||
557 | floppy= [HW] | 557 | floppy= [HW] |
558 | See Documentation/floppy.txt. | 558 | See Documentation/floppy.txt. |
559 | 559 | ||
560 | ftape= [HW] Floppy Tape subsystem debugging options. | ||
561 | See Documentation/ftape.txt. | ||
562 | |||
563 | gamecon.map[2|3]= | 560 | gamecon.map[2|3]= |
564 | [HW,JOY] Multisystem joystick and NES/SNES/PSX pad | 561 | [HW,JOY] Multisystem joystick and NES/SNES/PSX pad |
565 | support via parallel port (up to 5 devices per port) | 562 | support via parallel port (up to 5 devices per port) |
diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO index d684a6ac69a8..22f82f21bc60 100644 --- a/Documentation/s390/CommonIO +++ b/Documentation/s390/CommonIO | |||
@@ -74,7 +74,7 @@ Command line parameters | |||
74 | 74 | ||
75 | Note: While already known devices can be added to the list of devices to be | 75 | Note: While already known devices can be added to the list of devices to be |
76 | ignored, there will be no effect on then. However, if such a device | 76 | ignored, there will be no effect on then. However, if such a device |
77 | disappears and then reappeares, it will then be ignored. | 77 | disappears and then reappears, it will then be ignored. |
78 | 78 | ||
79 | For example, | 79 | For example, |
80 | "echo add 0.0.a000-0.0.accc, 0.0.af00-0.0.afff > /proc/cio_ignore" | 80 | "echo add 0.0.a000-0.0.accc, 0.0.af00-0.0.afff > /proc/cio_ignore" |
@@ -82,7 +82,7 @@ Command line parameters | |||
82 | devices. | 82 | devices. |
83 | 83 | ||
84 | The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward | 84 | The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward |
85 | compatibilty, by the device number in hexadecimal (0xabcd or abcd). | 85 | compatibility, by the device number in hexadecimal (0xabcd or abcd). |
86 | 86 | ||
87 | 87 | ||
88 | * /proc/s390dbf/cio_*/ (S/390 debug feature) | 88 | * /proc/s390dbf/cio_*/ (S/390 debug feature) |
diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt index 4dd25ee549e9..3f9ddbc23b27 100644 --- a/Documentation/s390/Debugging390.txt +++ b/Documentation/s390/Debugging390.txt | |||
@@ -7,7 +7,7 @@ | |||
7 | 7 | ||
8 | Overview of Document: | 8 | Overview of Document: |
9 | ===================== | 9 | ===================== |
10 | This document is intended to give an good overview of how to debug | 10 | This document is intended to give a good overview of how to debug |
11 | Linux for s/390 & z/Architecture. It isn't intended as a complete reference & not a | 11 | Linux for s/390 & z/Architecture. It isn't intended as a complete reference & not a |
12 | tutorial on the fundamentals of C & assembly. It doesn't go into | 12 | tutorial on the fundamentals of C & assembly. It doesn't go into |
13 | 390 IO in any detail. It is intended to complement the documents in the | 13 | 390 IO in any detail. It is intended to complement the documents in the |
@@ -300,7 +300,7 @@ On z/Architecture our page indexes are now 2k in size | |||
300 | but only mess with 2 segment indices each time we mess with | 300 | but only mess with 2 segment indices each time we mess with |
301 | a PMD. | 301 | a PMD. |
302 | 302 | ||
303 | 3) As z/Architecture supports upto a massive 5-level page table lookup we | 303 | 3) As z/Architecture supports up to a massive 5-level page table lookup we |
304 | can only use 3 currently on Linux ( as this is all the generic kernel | 304 | can only use 3 currently on Linux ( as this is all the generic kernel |
305 | currently supports ) however this may change in future | 305 | currently supports ) however this may change in future |
306 | this allows us to access ( according to my sums ) | 306 | this allows us to access ( according to my sums ) |
@@ -502,7 +502,7 @@ Notes: | |||
502 | ------ | 502 | ------ |
503 | 1) The only requirement is that registers which are used | 503 | 1) The only requirement is that registers which are used |
504 | by the callee are saved, e.g. the compiler is perfectly | 504 | by the callee are saved, e.g. the compiler is perfectly |
505 | capible of using r11 for purposes other than a frame a | 505 | capable of using r11 for purposes other than a frame a |
506 | frame pointer if a frame pointer is not needed. | 506 | frame pointer if a frame pointer is not needed. |
507 | 2) In functions with variable arguments e.g. printf the calling procedure | 507 | 2) In functions with variable arguments e.g. printf the calling procedure |
508 | is identical to one without variable arguments & the same number of | 508 | is identical to one without variable arguments & the same number of |
@@ -846,7 +846,7 @@ of time searching for debugging info. The following self explanatory line should | |||
846 | instead if the code isn't compiled -g, as it is much faster: | 846 | instead if the code isn't compiled -g, as it is much faster: |
847 | objdump --disassemble-all --syms vmlinux > vmlinux.lst | 847 | objdump --disassemble-all --syms vmlinux > vmlinux.lst |
848 | 848 | ||
849 | As hard drive space is valuble most of us use the following approach. | 849 | As hard drive space is valuable most of us use the following approach. |
850 | 1) Look at the emitted psw on the console to find the crash address in the kernel. | 850 | 1) Look at the emitted psw on the console to find the crash address in the kernel. |
851 | 2) Look at the file System.map ( in the linux directory ) produced when building | 851 | 2) Look at the file System.map ( in the linux directory ) produced when building |
852 | the kernel to find the closest address less than the current PSW to find the | 852 | the kernel to find the closest address less than the current PSW to find the |
@@ -902,7 +902,7 @@ A. It is a tool for intercepting calls to the kernel & logging them | |||
902 | to a file & on the screen. | 902 | to a file & on the screen. |
903 | 903 | ||
904 | Q. What use is it ? | 904 | Q. What use is it ? |
905 | A. You can used it to find out what files a particular program opens. | 905 | A. You can use it to find out what files a particular program opens. |
906 | 906 | ||
907 | 907 | ||
908 | 908 | ||
@@ -911,7 +911,7 @@ Example 1 | |||
911 | If you wanted to know does ping work but didn't have the source | 911 | If you wanted to know does ping work but didn't have the source |
912 | strace ping -c 1 127.0.0.1 | 912 | strace ping -c 1 127.0.0.1 |
913 | & then look at the man pages for each of the syscalls below, | 913 | & then look at the man pages for each of the syscalls below, |
914 | ( In fact this is sometimes easier than looking at some spagetti | 914 | ( In fact this is sometimes easier than looking at some spaghetti |
915 | source which conditionally compiles for several architectures ). | 915 | source which conditionally compiles for several architectures ). |
916 | Not everything that it throws out needs to make sense immediately. | 916 | Not everything that it throws out needs to make sense immediately. |
917 | 917 | ||
@@ -1037,7 +1037,7 @@ e.g. man strace, man alarm, man socket. | |||
1037 | 1037 | ||
1038 | Performance Debugging | 1038 | Performance Debugging |
1039 | ===================== | 1039 | ===================== |
1040 | gcc is capible of compiling in profiling code just add the -p option | 1040 | gcc is capable of compiling in profiling code just add the -p option |
1041 | to the CFLAGS, this obviously affects program size & performance. | 1041 | to the CFLAGS, this obviously affects program size & performance. |
1042 | This can be used by the gprof gnu profiling tool or the | 1042 | This can be used by the gprof gnu profiling tool or the |
1043 | gcov the gnu code coverage tool ( code coverage is a means of testing | 1043 | gcov the gnu code coverage tool ( code coverage is a means of testing |
@@ -1419,7 +1419,7 @@ On a SMP guest issue a command to all CPUs try prefixing the command with cpu al | |||
1419 | To issue a command to a particular cpu try cpu <cpu number> e.g. | 1419 | To issue a command to a particular cpu try cpu <cpu number> e.g. |
1420 | CPU 01 TR I R 2000.3000 | 1420 | CPU 01 TR I R 2000.3000 |
1421 | If you are running on a guest with several cpus & you have a IO related problem | 1421 | If you are running on a guest with several cpus & you have a IO related problem |
1422 | & cannot follow the flow of code but you know it isnt smp related. | 1422 | & cannot follow the flow of code but you know it isn't smp related. |
1423 | from the bash prompt issue | 1423 | from the bash prompt issue |
1424 | shutdown -h now or halt. | 1424 | shutdown -h now or halt. |
1425 | do a Q CPUS to find out how many cpus you have | 1425 | do a Q CPUS to find out how many cpus you have |
@@ -1602,7 +1602,7 @@ V000FFFD0 00010400 80010802 8001085A 000FFFA0 | |||
1602 | our 3rd return address is 8001085A | 1602 | our 3rd return address is 8001085A |
1603 | 1603 | ||
1604 | as the 04B52002 looks suspiciously like rubbish it is fair to assume that the kernel entry routines | 1604 | as the 04B52002 looks suspiciously like rubbish it is fair to assume that the kernel entry routines |
1605 | for the sake of optimisation dont set up a backchain. | 1605 | for the sake of optimisation don't set up a backchain. |
1606 | 1606 | ||
1607 | now look at System.map to see if the addresses make any sense. | 1607 | now look at System.map to see if the addresses make any sense. |
1608 | 1608 | ||
@@ -1638,11 +1638,11 @@ more useful information. | |||
1638 | 1638 | ||
1639 | Unlike other bus architectures modern 390 systems do their IO using mostly | 1639 | Unlike other bus architectures modern 390 systems do their IO using mostly |
1640 | fibre optics & devices such as tapes & disks can be shared between several mainframes, | 1640 | fibre optics & devices such as tapes & disks can be shared between several mainframes, |
1641 | also S390 can support upto 65536 devices while a high end PC based system might be choking | 1641 | also S390 can support up to 65536 devices while a high end PC based system might be choking |
1642 | with around 64. Here is some of the common IO terminology | 1642 | with around 64. Here is some of the common IO terminology |
1643 | 1643 | ||
1644 | Subchannel: | 1644 | Subchannel: |
1645 | This is the logical number most IO commands use to talk to an IO device there can be upto | 1645 | This is the logical number most IO commands use to talk to an IO device there can be up to |
1646 | 0x10000 (65536) of these in a configuration typically there is a few hundred. Under VM | 1646 | 0x10000 (65536) of these in a configuration typically there is a few hundred. Under VM |
1647 | for simplicity they are allocated contiguously, however on the native hardware they are not | 1647 | for simplicity they are allocated contiguously, however on the native hardware they are not |
1648 | they typically stay consistent between boots provided no new hardware is inserted or removed. | 1648 | they typically stay consistent between boots provided no new hardware is inserted or removed. |
@@ -1651,7 +1651,7 @@ HALT SUBCHANNEL,MODIFY SUBCHANNEL,RESUME SUBCHANNEL,START SUBCHANNEL,STORE SUBCH | |||
1651 | TEST SUBCHANNEL ) we use this as the ID of the device we wish to talk to, the most | 1651 | TEST SUBCHANNEL ) we use this as the ID of the device we wish to talk to, the most |
1652 | important of these instructions are START SUBCHANNEL ( to start IO ), TEST SUBCHANNEL ( to check | 1652 | important of these instructions are START SUBCHANNEL ( to start IO ), TEST SUBCHANNEL ( to check |
1653 | whether the IO completed successfully ), & HALT SUBCHANNEL ( to kill IO ), a subchannel | 1653 | whether the IO completed successfully ), & HALT SUBCHANNEL ( to kill IO ), a subchannel |
1654 | can have up to 8 channel paths to a device this offers redunancy if one is not available. | 1654 | can have up to 8 channel paths to a device this offers redundancy if one is not available. |
1655 | 1655 | ||
1656 | 1656 | ||
1657 | Device Number: | 1657 | Device Number: |
@@ -1659,7 +1659,7 @@ This number remains static & Is closely tied to the hardware, there are 65536 of | |||
1659 | also they are made up of a CHPID ( Channel Path ID, the most significant 8 bits ) | 1659 | also they are made up of a CHPID ( Channel Path ID, the most significant 8 bits ) |
1660 | & another lsb 8 bits. These remain static even if more devices are inserted or removed | 1660 | & another lsb 8 bits. These remain static even if more devices are inserted or removed |
1661 | from the hardware, there is a 1 to 1 mapping between Subchannels & Device Numbers provided | 1661 | from the hardware, there is a 1 to 1 mapping between Subchannels & Device Numbers provided |
1662 | devices arent inserted or removed. | 1662 | devices aren't inserted or removed. |
1663 | 1663 | ||
1664 | Channel Control Words: | 1664 | Channel Control Words: |
1665 | CCWS are linked lists of instructions initially pointed to by an operation request block (ORB), | 1665 | CCWS are linked lists of instructions initially pointed to by an operation request block (ORB), |
@@ -1674,7 +1674,7 @@ concurrently, you check how the IO went on by issuing a TEST SUBCHANNEL at each | |||
1674 | from which you receive an Interruption response block (IRB). If you get channel & device end | 1674 | from which you receive an Interruption response block (IRB). If you get channel & device end |
1675 | status in the IRB without channel checks etc. your IO probably went okay. If you didn't you | 1675 | status in the IRB without channel checks etc. your IO probably went okay. If you didn't you |
1676 | probably need a doctor to examine the IRB & extended status word etc. | 1676 | probably need a doctor to examine the IRB & extended status word etc. |
1677 | If an error occurs, more sophistocated control units have a facitity known as | 1677 | If an error occurs, more sophisticated control units have a facility known as |
1678 | concurrent sense this means that if an error occurs Extended sense information will | 1678 | concurrent sense this means that if an error occurs Extended sense information will |
1679 | be presented in the Extended status word in the IRB if not you have to issue a | 1679 | be presented in the Extended status word in the IRB if not you have to issue a |
1680 | subsequent SENSE CCW command after the test subchannel. | 1680 | subsequent SENSE CCW command after the test subchannel. |
@@ -1749,7 +1749,7 @@ Interface (OEMI). | |||
1749 | This byte wide Parallel channel path/bus has parity & data on the "Bus" cable | 1749 | This byte wide Parallel channel path/bus has parity & data on the "Bus" cable |
1750 | & control lines on the "Tag" cable. These can operate in byte multiplex mode for | 1750 | & control lines on the "Tag" cable. These can operate in byte multiplex mode for |
1751 | sharing between several slow devices or burst mode & monopolize the channel for the | 1751 | sharing between several slow devices or burst mode & monopolize the channel for the |
1752 | whole burst. Upto 256 devices can be addressed on one of these cables. These cables are | 1752 | whole burst. Up to 256 devices can be addressed on one of these cables. These cables are |
1753 | about one inch in diameter. The maximum unextended length supported by these cables is | 1753 | about one inch in diameter. The maximum unextended length supported by these cables is |
1754 | 125 Meters but this can be extended up to 2km with a fibre optic channel extended | 1754 | 125 Meters but this can be extended up to 2km with a fibre optic channel extended |
1755 | such as a 3044. The maximum burst speed supported is 4.5 megabytes per second however | 1755 | such as a 3044. The maximum burst speed supported is 4.5 megabytes per second however |
@@ -1759,7 +1759,7 @@ One of these paths can be daisy chained to up to 8 control units. | |||
1759 | 1759 | ||
1760 | ESCON if fibre optic it is also called FICON | 1760 | ESCON if fibre optic it is also called FICON |
1761 | Was introduced by IBM in 1990. Has 2 fibre optic cables & uses either leds or lasers | 1761 | Was introduced by IBM in 1990. Has 2 fibre optic cables & uses either leds or lasers |
1762 | for communication at a signaling rate of upto 200 megabits/sec. As 10bits are transferred | 1762 | for communication at a signaling rate of up to 200 megabits/sec. As 10bits are transferred |
1763 | for every 8 bits info this drops to 160 megabits/sec & to 18.6 Megabytes/sec once | 1763 | for every 8 bits info this drops to 160 megabits/sec & to 18.6 Megabytes/sec once |
1764 | control info & CRC are added. ESCON only operates in burst mode. | 1764 | control info & CRC are added. ESCON only operates in burst mode. |
1765 | 1765 | ||
@@ -1767,7 +1767,7 @@ ESCONs typical max cable length is 3km for the led version & 20km for the laser | |||
1767 | known as XDF ( extended distance facility ). This can be further extended by using an | 1767 | known as XDF ( extended distance facility ). This can be further extended by using an |
1768 | ESCON director which triples the above mentioned ranges. Unlike Bus & Tag as ESCON is | 1768 | ESCON director which triples the above mentioned ranges. Unlike Bus & Tag as ESCON is |
1769 | serial it uses a packet switching architecture the standard Bus & Tag control protocol | 1769 | serial it uses a packet switching architecture the standard Bus & Tag control protocol |
1770 | is however present within the packets. Upto 256 devices can be attached to each control | 1770 | is however present within the packets. Up to 256 devices can be attached to each control |
1771 | unit that uses one of these interfaces. | 1771 | unit that uses one of these interfaces. |
1772 | 1772 | ||
1773 | Common 390 Devices include: | 1773 | Common 390 Devices include: |
@@ -2050,7 +2050,7 @@ list test.c:1,10 | |||
2050 | 2050 | ||
2051 | directory: | 2051 | directory: |
2052 | Adds directories to be searched for source if gdb cannot find the source. | 2052 | Adds directories to be searched for source if gdb cannot find the source. |
2053 | (note it is a bit sensititive about slashes) | 2053 | (note it is a bit sensitive about slashes) |
2054 | e.g. To add the root of the filesystem to the searchpath do | 2054 | e.g. To add the root of the filesystem to the searchpath do |
2055 | directory // | 2055 | directory // |
2056 | 2056 | ||
@@ -2152,7 +2152,7 @@ program as if it just crashed on your system, it is usually called core & create | |||
2152 | current working directory. | 2152 | current working directory. |
2153 | This is very useful in that a customer can mail a core dump to a technical support department | 2153 | This is very useful in that a customer can mail a core dump to a technical support department |
2154 | & the technical support department can reconstruct what happened. | 2154 | & the technical support department can reconstruct what happened. |
2155 | Provided the have an identical copy of this program with debugging symbols compiled in & | 2155 | Provided they have an identical copy of this program with debugging symbols compiled in & |
2156 | the source base of this build is available. | 2156 | the source base of this build is available. |
2157 | In short it is far more useful than something like a crash log could ever hope to be. | 2157 | In short it is far more useful than something like a crash log could ever hope to be. |
2158 | 2158 | ||
diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt index 32a96cc39215..05a2b4f7e38f 100644 --- a/Documentation/s390/cds.txt +++ b/Documentation/s390/cds.txt | |||
@@ -98,7 +98,7 @@ The following chapters describe the I/O related interface routines the | |||
98 | Linux/390 common device support (CDS) provides to allow for device specific | 98 | Linux/390 common device support (CDS) provides to allow for device specific |
99 | driver implementations on the IBM ESA/390 hardware platform. Those interfaces | 99 | driver implementations on the IBM ESA/390 hardware platform. Those interfaces |
100 | intend to provide the functionality required by every device driver | 100 | intend to provide the functionality required by every device driver |
101 | implementaion to allow to drive a specific hardware device on the ESA/390 | 101 | implementation to allow to drive a specific hardware device on the ESA/390 |
102 | platform. Some of the interface routines are specific to Linux/390 and some | 102 | platform. Some of the interface routines are specific to Linux/390 and some |
103 | of them can be found on other Linux platforms implementations too. | 103 | of them can be found on other Linux platforms implementations too. |
104 | Miscellaneous function prototypes, data declarations, and macro definitions | 104 | Miscellaneous function prototypes, data declarations, and macro definitions |
@@ -114,7 +114,7 @@ the ESA/390 architecture has implemented a so called channel subsystem, that | |||
114 | provides a unified view of the devices physically attached to the systems. | 114 | provides a unified view of the devices physically attached to the systems. |
115 | Though the ESA/390 hardware platform knows about a huge variety of different | 115 | Though the ESA/390 hardware platform knows about a huge variety of different |
116 | peripheral attachments like disk devices (aka. DASDs), tapes, communication | 116 | peripheral attachments like disk devices (aka. DASDs), tapes, communication |
117 | controllers, etc. they can all by accessed by a well defined access method and | 117 | controllers, etc. they can all be accessed by a well defined access method and |
118 | they are presenting I/O completion a unified way : I/O interruptions. Every | 118 | they are presenting I/O completion a unified way : I/O interruptions. Every |
119 | single device is uniquely identified to the system by a so called subchannel, | 119 | single device is uniquely identified to the system by a so called subchannel, |
120 | where the ESA/390 architecture allows for 64k devices be attached. | 120 | where the ESA/390 architecture allows for 64k devices be attached. |
@@ -338,7 +338,7 @@ DOIO_REPORT_ALL - report all interrupt conditions | |||
338 | The ccw_device_start() function returns : | 338 | The ccw_device_start() function returns : |
339 | 339 | ||
340 | 0 - successful completion or request successfully initiated | 340 | 0 - successful completion or request successfully initiated |
341 | -EBUSY - The device is currently processing a previous I/O request, or ther is | 341 | -EBUSY - The device is currently processing a previous I/O request, or there is |
342 | a status pending at the device. | 342 | a status pending at the device. |
343 | -ENODEV - cdev is invalid, the device is not operational or the ccw_device is | 343 | -ENODEV - cdev is invalid, the device is not operational or the ccw_device is |
344 | not online. | 344 | not online. |
@@ -361,7 +361,7 @@ first: | |||
361 | -EIO: the common I/O layer terminated the request due to an error state | 361 | -EIO: the common I/O layer terminated the request due to an error state |
362 | 362 | ||
363 | If the concurrent sense flag in the extended status word in the irb is set, the | 363 | If the concurrent sense flag in the extended status word in the irb is set, the |
364 | field irb->scsw.count describes the numer of device specific sense bytes | 364 | field irb->scsw.count describes the number of device specific sense bytes |
365 | available in the extended control word irb->scsw.ecw[0]. No device sensing by | 365 | available in the extended control word irb->scsw.ecw[0]. No device sensing by |
366 | the device driver itself is required. | 366 | the device driver itself is required. |
367 | 367 | ||
@@ -410,7 +410,7 @@ ccw_device_start() must be called disabled and with the ccw device lock held. | |||
410 | 410 | ||
411 | The device driver is allowed to issue the next ccw_device_start() call from | 411 | The device driver is allowed to issue the next ccw_device_start() call from |
412 | within its interrupt handler already. It is not required to schedule a | 412 | within its interrupt handler already. It is not required to schedule a |
413 | bottom-half, unless an non deterministically long running error recovery procedure | 413 | bottom-half, unless a non deterministically long running error recovery procedure |
414 | or similar needs to be scheduled. During I/O processing the Linux/390 generic | 414 | or similar needs to be scheduled. During I/O processing the Linux/390 generic |
415 | I/O device driver support has already obtained the IRQ lock, i.e. the handler | 415 | I/O device driver support has already obtained the IRQ lock, i.e. the handler |
416 | must not try to obtain it again when calling ccw_device_start() or we end in a | 416 | must not try to obtain it again when calling ccw_device_start() or we end in a |
@@ -431,7 +431,7 @@ information prior to device-end the device driver urgently relies on. In this | |||
431 | case all I/O interruptions are presented to the device driver until final | 431 | case all I/O interruptions are presented to the device driver until final |
432 | status is recognized. | 432 | status is recognized. |
433 | 433 | ||
434 | If a device is able to recover from asynchronosly presented I/O errors, it can | 434 | If a device is able to recover from asynchronously presented I/O errors, it can |
435 | perform overlapping I/O using the DOIO_EARLY_NOTIFICATION flag. While some | 435 | perform overlapping I/O using the DOIO_EARLY_NOTIFICATION flag. While some |
436 | devices always report channel-end and device-end together, with a single | 436 | devices always report channel-end and device-end together, with a single |
437 | interrupt, others present primary status (channel-end) when the channel is | 437 | interrupt, others present primary status (channel-end) when the channel is |
diff --git a/Documentation/s390/crypto/crypto-API.txt b/Documentation/s390/crypto/crypto-API.txt index 41a8b07da05a..71ae6ca9f2c2 100644 --- a/Documentation/s390/crypto/crypto-API.txt +++ b/Documentation/s390/crypto/crypto-API.txt | |||
@@ -17,8 +17,8 @@ arch/s390/crypto directory. | |||
17 | 2. Probing for availability of MSA | 17 | 2. Probing for availability of MSA |
18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
19 | It should be possible to use Kernels with the z990 crypto implementations both | 19 | It should be possible to use Kernels with the z990 crypto implementations both |
20 | on machines with MSA available an on those without MSA (pre z990 or z990 | 20 | on machines with MSA available and on those without MSA (pre z990 or z990 |
21 | without MSA). Therefore a simple probing mechanisms has been implemented: | 21 | without MSA). Therefore a simple probing mechanism has been implemented: |
22 | In the init function of each crypto module the availability of MSA and of the | 22 | In the init function of each crypto module the availability of MSA and of the |
23 | respective crypto algorithm in particular will be tested. If the algorithm is | 23 | respective crypto algorithm in particular will be tested. If the algorithm is |
24 | available the module will load and register its algorithm with the crypto API. | 24 | available the module will load and register its algorithm with the crypto API. |
@@ -26,7 +26,7 @@ available the module will load and register its algorithm with the crypto API. | |||
26 | If the respective crypto algorithm is not available, the init function will | 26 | If the respective crypto algorithm is not available, the init function will |
27 | return -ENOSYS. In that case a fallback to the standard software implementation | 27 | return -ENOSYS. In that case a fallback to the standard software implementation |
28 | of the crypto algorithm must be taken ( -> the standard crypto modules are | 28 | of the crypto algorithm must be taken ( -> the standard crypto modules are |
29 | also build when compiling the kernel). | 29 | also built when compiling the kernel). |
30 | 30 | ||
31 | 31 | ||
32 | 3. Ensuring z990 crypto module preference | 32 | 3. Ensuring z990 crypto module preference |
diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt index 000230cd26db..0eb7c58916de 100644 --- a/Documentation/s390/s390dbf.txt +++ b/Documentation/s390/s390dbf.txt | |||
@@ -36,7 +36,7 @@ switches to the next debug area. This is done in order to be sure | |||
36 | that the records which describe the origin of the exception are not | 36 | that the records which describe the origin of the exception are not |
37 | overwritten when a wrap around for the current area occurs. | 37 | overwritten when a wrap around for the current area occurs. |
38 | 38 | ||
39 | The debug areas itselve are also ordered in form of a ring buffer. | 39 | The debug areas themselves are also ordered in form of a ring buffer. |
40 | When an exception is thrown in the last debug area, the following debug | 40 | When an exception is thrown in the last debug area, the following debug |
41 | entries are then written again in the very first area. | 41 | entries are then written again in the very first area. |
42 | 42 | ||
@@ -55,7 +55,7 @@ The debug logs can be inspected in a live system through entries in | |||
55 | the debugfs-filesystem. Under the toplevel directory "s390dbf" there is | 55 | the debugfs-filesystem. Under the toplevel directory "s390dbf" there is |
56 | a directory for each registered component, which is named like the | 56 | a directory for each registered component, which is named like the |
57 | corresponding component. The debugfs normally should be mounted to | 57 | corresponding component. The debugfs normally should be mounted to |
58 | /sys/kernel/debug therefore the debug feature can be accessed unter | 58 | /sys/kernel/debug therefore the debug feature can be accessed under |
59 | /sys/kernel/debug/s390dbf. | 59 | /sys/kernel/debug/s390dbf. |
60 | 60 | ||
61 | The content of the directories are files which represent different views | 61 | The content of the directories are files which represent different views |
@@ -87,11 +87,11 @@ There are currently 2 possible triggers, which stop the debug feature | |||
87 | globally. The first possibility is to use the "debug_active" sysctl. If | 87 | globally. The first possibility is to use the "debug_active" sysctl. If |
88 | set to 1 the debug feature is running. If "debug_active" is set to 0 the | 88 | set to 1 the debug feature is running. If "debug_active" is set to 0 the |
89 | debug feature is turned off. | 89 | debug feature is turned off. |
90 | The second trigger which stops the debug feature is an kernel oops. | 90 | The second trigger which stops the debug feature is a kernel oops. |
91 | That prevents the debug feature from overwriting debug information that | 91 | That prevents the debug feature from overwriting debug information that |
92 | happened before the oops. After an oops you can reactivate the debug feature | 92 | happened before the oops. After an oops you can reactivate the debug feature |
93 | by piping 1 to /proc/sys/s390dbf/debug_active. Nevertheless, its not | 93 | by piping 1 to /proc/sys/s390dbf/debug_active. Nevertheless, its not |
94 | suggested to use an oopsed kernel in an production environment. | 94 | suggested to use an oopsed kernel in a production environment. |
95 | If you want to disallow the deactivation of the debug feature, you can use | 95 | If you want to disallow the deactivation of the debug feature, you can use |
96 | the "debug_stoppable" sysctl. If you set "debug_stoppable" to 0 the debug | 96 | the "debug_stoppable" sysctl. If you set "debug_stoppable" to 0 the debug |
97 | feature cannot be stopped. If the debug feature is already stopped, it | 97 | feature cannot be stopped. If the debug feature is already stopped, it |
diff --git a/MAINTAINERS b/MAINTAINERS index 45df5d4e2ab3..8385a69138a8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1166,11 +1166,6 @@ P: David Howells | |||
1166 | M: dhowells@redhat.com | 1166 | M: dhowells@redhat.com |
1167 | S: Maintained | 1167 | S: Maintained |
1168 | 1168 | ||
1169 | FTAPE/QIC-117 | ||
1170 | L: linux-tape@vger.kernel.org | ||
1171 | W: http://sourceforge.net/projects/ftape | ||
1172 | S: Orphan | ||
1173 | |||
1174 | FUSE: FILESYSTEM IN USERSPACE | 1169 | FUSE: FILESYSTEM IN USERSPACE |
1175 | P: Miklos Szeredi | 1170 | P: Miklos Szeredi |
1176 | M: miklos@szeredi.hu | 1171 | M: miklos@szeredi.hu |
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index c1bc22c6d0d8..aa70dde54228 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig | |||
@@ -173,7 +173,7 @@ config CLOCK_DIV | |||
173 | On many SoC style CPUs the master CPU clock is also used to drive | 173 | On many SoC style CPUs the master CPU clock is also used to drive |
174 | on-chip peripherals. The clock that is distributed to these | 174 | on-chip peripherals. The clock that is distributed to these |
175 | peripherals is sometimes a fixed ratio of the master clock | 175 | peripherals is sometimes a fixed ratio of the master clock |
176 | frequency. If so then set this to the divider ration of the | 176 | frequency. If so then set this to the divider ratio of the |
177 | master clock to the peripheral clock. If not sure then select 1. | 177 | master clock to the peripheral clock. If not sure then select 1. |
178 | 178 | ||
179 | config OLDMASK | 179 | config OLDMASK |
@@ -192,7 +192,7 @@ config PILOT3 | |||
192 | Support for the Palm Pilot 1000/5000, Personal/Pro and PalmIII. | 192 | Support for the Palm Pilot 1000/5000, Personal/Pro and PalmIII. |
193 | 193 | ||
194 | config XCOPILOT_BUGS | 194 | config XCOPILOT_BUGS |
195 | bool " (X)Copilot support" | 195 | bool "(X)Copilot support" |
196 | depends on PILOT3 | 196 | depends on PILOT3 |
197 | help | 197 | help |
198 | Support the bugs of Xcopilot. | 198 | Support the bugs of Xcopilot. |
@@ -216,20 +216,20 @@ config DRAGEN2 | |||
216 | Support for the DragenEngine II board. | 216 | Support for the DragenEngine II board. |
217 | 217 | ||
218 | config DIRECT_IO_ACCESS | 218 | config DIRECT_IO_ACCESS |
219 | bool " Allow user to access IO directly" | 219 | bool "Allow user to access IO directly" |
220 | depends on (UCSIMM || UCDIMM || DRAGEN2) | 220 | depends on (UCSIMM || UCDIMM || DRAGEN2) |
221 | help | 221 | help |
222 | Disable the CPU internal registers protection in user mode, | 222 | Disable the CPU internal registers protection in user mode, |
223 | to allow a user application to read/write them. | 223 | to allow a user application to read/write them. |
224 | 224 | ||
225 | config INIT_LCD | 225 | config INIT_LCD |
226 | bool " Initialize LCD" | 226 | bool "Initialize LCD" |
227 | depends on (UCSIMM || UCDIMM || DRAGEN2) | 227 | depends on (UCSIMM || UCDIMM || DRAGEN2) |
228 | help | 228 | help |
229 | Initialize the LCD controller of the 68x328 processor. | 229 | Initialize the LCD controller of the 68x328 processor. |
230 | 230 | ||
231 | config MEMORY_RESERVE | 231 | config MEMORY_RESERVE |
232 | int " Memory reservation (MiB)" | 232 | int "Memory reservation (MiB)" |
233 | depends on (UCSIMM || UCDIMM) | 233 | depends on (UCSIMM || UCDIMM) |
234 | help | 234 | help |
235 | Reserve certain memory regions on 68x328 based boards. | 235 | Reserve certain memory regions on 68x328 based boards. |
@@ -409,7 +409,7 @@ config MOD5272 | |||
409 | Support for the Netburner MOD-5272 board. | 409 | Support for the Netburner MOD-5272 board. |
410 | 410 | ||
411 | config ROMFS_FROM_ROM | 411 | config ROMFS_FROM_ROM |
412 | bool " ROMFS image not RAM resident" | 412 | bool "ROMFS image not RAM resident" |
413 | depends on (NETtel || SNAPGEAR) | 413 | depends on (NETtel || SNAPGEAR) |
414 | help | 414 | help |
415 | The ROMfs filesystem will stay resident in the FLASH/ROM, not be | 415 | The ROMfs filesystem will stay resident in the FLASH/ROM, not be |
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c index c18a83306953..941955dc3b7c 100644 --- a/arch/m68knommu/kernel/process.c +++ b/arch/m68knommu/kernel/process.c | |||
@@ -290,7 +290,7 @@ void dump(struct pt_regs *fp) | |||
290 | unsigned char *tp; | 290 | unsigned char *tp; |
291 | int i; | 291 | int i; |
292 | 292 | ||
293 | printk(KERN_EMERG "\nCURRENT PROCESS:\n\n"); | 293 | printk(KERN_EMERG "\n" KERN_EMERG "CURRENT PROCESS:\n" KERN_EMERG "\n"); |
294 | printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid); | 294 | printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid); |
295 | 295 | ||
296 | if (current->mm) { | 296 | if (current->mm) { |
@@ -301,7 +301,8 @@ void dump(struct pt_regs *fp) | |||
301 | (int) current->mm->end_data, | 301 | (int) current->mm->end_data, |
302 | (int) current->mm->end_data, | 302 | (int) current->mm->end_data, |
303 | (int) current->mm->brk); | 303 | (int) current->mm->brk); |
304 | printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n", | 304 | printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n" |
305 | KERN_EMERG "\n", | ||
305 | (int) current->mm->start_stack, | 306 | (int) current->mm->start_stack, |
306 | (int)(((unsigned long) current) + THREAD_SIZE)); | 307 | (int)(((unsigned long) current) + THREAD_SIZE)); |
307 | } | 308 | } |
@@ -312,36 +313,35 @@ void dump(struct pt_regs *fp) | |||
312 | fp->d0, fp->d1, fp->d2, fp->d3); | 313 | fp->d0, fp->d1, fp->d2, fp->d3); |
313 | printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", | 314 | printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", |
314 | fp->d4, fp->d5, fp->a0, fp->a1); | 315 | fp->d4, fp->d5, fp->a0, fp->a1); |
315 | printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %08x\n", (unsigned int) rdusp(), | 316 | printk(KERN_EMERG "\n" KERN_EMERG "USP: %08x TRAPFRAME: %08x\n", |
316 | (unsigned int) fp); | 317 | (unsigned int) rdusp(), (unsigned int) fp); |
317 | 318 | ||
318 | printk(KERN_EMERG "\nCODE:"); | 319 | printk(KERN_EMERG "\n" KERN_EMERG "CODE:"); |
319 | tp = ((unsigned char *) fp->pc) - 0x20; | 320 | tp = ((unsigned char *) fp->pc) - 0x20; |
320 | for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { | 321 | for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { |
321 | if ((i % 0x10) == 0) | 322 | if ((i % 0x10) == 0) |
322 | printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); | 323 | printk("\n" KERN_EMERG "%08x: ", (int) (tp + i)); |
323 | printk(KERN_EMERG "%08x ", (int) *sp++); | 324 | printk("%08x ", (int) *sp++); |
324 | } | 325 | } |
325 | printk(KERN_EMERG "\n"); | 326 | printk("\n" KERN_EMERG "\n"); |
326 | 327 | ||
327 | printk(KERN_EMERG "\nKERNEL STACK:"); | 328 | printk(KERN_EMERG "KERNEL STACK:"); |
328 | tp = ((unsigned char *) fp) - 0x40; | 329 | tp = ((unsigned char *) fp) - 0x40; |
329 | for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { | 330 | for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { |
330 | if ((i % 0x10) == 0) | 331 | if ((i % 0x10) == 0) |
331 | printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); | 332 | printk("\n" KERN_EMERG "%08x: ", (int) (tp + i)); |
332 | printk(KERN_EMERG "%08x ", (int) *sp++); | 333 | printk("%08x ", (int) *sp++); |
333 | } | 334 | } |
334 | printk(KERN_EMERG "\n"); | 335 | printk("\n" KERN_EMERG "\n"); |
335 | printk(KERN_EMERG "\n"); | ||
336 | 336 | ||
337 | printk(KERN_EMERG "\nUSER STACK:"); | 337 | printk(KERN_EMERG "USER STACK:"); |
338 | tp = (unsigned char *) (rdusp() - 0x10); | 338 | tp = (unsigned char *) (rdusp() - 0x10); |
339 | for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { | 339 | for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { |
340 | if ((i % 0x10) == 0) | 340 | if ((i % 0x10) == 0) |
341 | printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); | 341 | printk("\n" KERN_EMERG "%08x: ", (int) (tp + i)); |
342 | printk(KERN_EMERG "%08x ", (int) *sp++); | 342 | printk("%08x ", (int) *sp++); |
343 | } | 343 | } |
344 | printk(KERN_EMERG "\n\n"); | 344 | printk("\n" KERN_EMERG "\n"); |
345 | } | 345 | } |
346 | 346 | ||
347 | /* | 347 | /* |
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c index 7b21959eaeae..9cf2e4d1fc77 100644 --- a/arch/m68knommu/kernel/setup.c +++ b/arch/m68knommu/kernel/setup.c | |||
@@ -36,10 +36,7 @@ | |||
36 | #include <asm/setup.h> | 36 | #include <asm/setup.h> |
37 | #include <asm/irq.h> | 37 | #include <asm/irq.h> |
38 | #include <asm/machdep.h> | 38 | #include <asm/machdep.h> |
39 | |||
40 | #ifdef CONFIG_BLK_DEV_INITRD | ||
41 | #include <asm/pgtable.h> | 39 | #include <asm/pgtable.h> |
42 | #endif | ||
43 | 40 | ||
44 | unsigned long memory_start; | 41 | unsigned long memory_start; |
45 | unsigned long memory_end; | 42 | unsigned long memory_end; |
diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c index c3494b8447d1..3265b2d734db 100644 --- a/arch/m68knommu/kernel/sys_m68k.c +++ b/arch/m68knommu/kernel/sys_m68k.c | |||
@@ -137,7 +137,7 @@ asmlinkage int old_select(struct sel_arg_struct *arg) | |||
137 | asmlinkage int sys_ipc (uint call, int first, int second, | 137 | asmlinkage int sys_ipc (uint call, int first, int second, |
138 | int third, void *ptr, long fifth) | 138 | int third, void *ptr, long fifth) |
139 | { | 139 | { |
140 | int version; | 140 | int version, ret; |
141 | 141 | ||
142 | version = call >> 16; /* hack for backward compatibility */ | 142 | version = call >> 16; /* hack for backward compatibility */ |
143 | call &= 0xffff; | 143 | call &= 0xffff; |
@@ -190,6 +190,27 @@ asmlinkage int sys_ipc (uint call, int first, int second, | |||
190 | default: | 190 | default: |
191 | return -EINVAL; | 191 | return -EINVAL; |
192 | } | 192 | } |
193 | if (call <= SHMCTL) | ||
194 | switch (call) { | ||
195 | case SHMAT: | ||
196 | switch (version) { | ||
197 | default: { | ||
198 | ulong raddr; | ||
199 | ret = do_shmat (first, ptr, second, &raddr); | ||
200 | if (ret) | ||
201 | return ret; | ||
202 | return put_user (raddr, (ulong __user *) third); | ||
203 | } | ||
204 | } | ||
205 | case SHMDT: | ||
206 | return sys_shmdt (ptr); | ||
207 | case SHMGET: | ||
208 | return sys_shmget (first, second, third); | ||
209 | case SHMCTL: | ||
210 | return sys_shmctl (first, second, ptr); | ||
211 | default: | ||
212 | return -ENOSYS; | ||
213 | } | ||
193 | 214 | ||
194 | return -EINVAL; | 215 | return -EINVAL; |
195 | } | 216 | } |
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c index 17649d2543ef..9129b3a5258b 100644 --- a/arch/m68knommu/kernel/traps.c +++ b/arch/m68knommu/kernel/traps.c | |||
@@ -127,11 +127,12 @@ void show_stack(struct task_struct *task, unsigned long *stack) | |||
127 | if (stack + 1 > endstack) | 127 | if (stack + 1 > endstack) |
128 | break; | 128 | break; |
129 | if (i % 8 == 0) | 129 | if (i % 8 == 0) |
130 | printk(KERN_EMERG "\n "); | 130 | printk("\n" KERN_EMERG " "); |
131 | printk(KERN_EMERG " %08lx", *stack++); | 131 | printk(" %08lx", *stack++); |
132 | } | 132 | } |
133 | printk("\n"); | ||
133 | 134 | ||
134 | printk(KERN_EMERG "\nCall Trace:"); | 135 | printk(KERN_EMERG "Call Trace:"); |
135 | i = 0; | 136 | i = 0; |
136 | while (stack + 1 <= endstack) { | 137 | while (stack + 1 <= endstack) { |
137 | addr = *stack++; | 138 | addr = *stack++; |
@@ -146,12 +147,12 @@ void show_stack(struct task_struct *task, unsigned long *stack) | |||
146 | if (((addr >= (unsigned long) &_start) && | 147 | if (((addr >= (unsigned long) &_start) && |
147 | (addr <= (unsigned long) &_etext))) { | 148 | (addr <= (unsigned long) &_etext))) { |
148 | if (i % 4 == 0) | 149 | if (i % 4 == 0) |
149 | printk(KERN_EMERG "\n "); | 150 | printk("\n" KERN_EMERG " "); |
150 | printk(KERN_EMERG " [<%08lx>]", addr); | 151 | printk(" [<%08lx>]", addr); |
151 | i++; | 152 | i++; |
152 | } | 153 | } |
153 | } | 154 | } |
154 | printk(KERN_EMERG "\n"); | 155 | printk("\n"); |
155 | } | 156 | } |
156 | 157 | ||
157 | void bad_super_trap(struct frame *fp) | 158 | void bad_super_trap(struct frame *fp) |
diff --git a/arch/m68knommu/platform/5307/head.S b/arch/m68knommu/platform/5307/head.S index f2edb6498cd9..b9aa0ca29bfb 100644 --- a/arch/m68knommu/platform/5307/head.S +++ b/arch/m68knommu/platform/5307/head.S | |||
@@ -64,6 +64,26 @@ | |||
64 | negl %d0 /* negate bits */ | 64 | negl %d0 /* negate bits */ |
65 | .endm | 65 | .endm |
66 | 66 | ||
67 | #elif defined(CONFIG_M520x) | ||
68 | .macro GET_MEM_SIZE | ||
69 | clrl %d0 | ||
70 | movel MCF_MBAR+MCFSIM_SDCS0, %d2 /* Get SDRAM chip select 0 config */ | ||
71 | andl #0x1f, %d2 /* Get only the chip select size */ | ||
72 | beq 3f /* Check if it is enabled */ | ||
73 | addql #1, %d2 /* Form exponent */ | ||
74 | moveql #1, %d0 | ||
75 | lsll %d2, %d0 /* 2 ^ exponent */ | ||
76 | 3: | ||
77 | movel MCF_MBAR+MCFSIM_SDCS1, %d2 /* Get SDRAM chip select 1 config */ | ||
78 | andl #0x1f, %d2 /* Get only the chip select size */ | ||
79 | beq 4f /* Check if it is enabled */ | ||
80 | addql #1, %d2 /* Form exponent */ | ||
81 | moveql #1, %d1 | ||
82 | lsll %d2, %d1 /* 2 ^ exponent */ | ||
83 | addl %d1, %d0 /* Total size of SDRAM in d0 */ | ||
84 | 4: | ||
85 | .endm | ||
86 | |||
67 | #else | 87 | #else |
68 | #error "ERROR: I don't know how to probe your boards memory size?" | 88 | #error "ERROR: I don't know how to probe your boards memory size?" |
69 | #endif | 89 | #endif |
diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68knommu/platform/68360/head-ram.S index 2ea51479f13a..2ef06242398b 100644 --- a/arch/m68knommu/platform/68360/head-ram.S +++ b/arch/m68knommu/platform/68360/head-ram.S | |||
@@ -25,6 +25,7 @@ | |||
25 | .global _periph_base | 25 | .global _periph_base |
26 | 26 | ||
27 | #define RAMEND (CONFIG_RAMBASE + CONFIG_RAMSIZE) | 27 | #define RAMEND (CONFIG_RAMBASE + CONFIG_RAMSIZE) |
28 | #define ROMEND (CONFIG_ROMBASE + CONFIG_ROMSIZE) | ||
28 | 29 | ||
29 | #define REGB 0x1000 | 30 | #define REGB 0x1000 |
30 | #define PEPAR (_dprbase + REGB + 0x0016) | 31 | #define PEPAR (_dprbase + REGB + 0x0016) |
@@ -175,7 +176,7 @@ configure_chip_select_0: | |||
175 | move.l %d0, BR0 | 176 | move.l %d0, BR0 |
176 | 177 | ||
177 | configure_chip_select_1: | 178 | configure_chip_select_1: |
178 | move.l #__rom_end, %d0 | 179 | move.l #ROMEND, %d0 |
179 | subi.l #__rom_start, %d0 | 180 | subi.l #__rom_start, %d0 |
180 | subq.l #0x01, %d0 | 181 | subq.l #0x01, %d0 |
181 | eori.l #SIM_OR_MASK, %d0 | 182 | eori.l #SIM_OR_MASK, %d0 |
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 245b81bc7157..583d9ff0a571 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -33,9 +33,6 @@ config GENERIC_CALIBRATE_DELAY | |||
33 | config GENERIC_TIME | 33 | config GENERIC_TIME |
34 | def_bool y | 34 | def_bool y |
35 | 35 | ||
36 | config GENERIC_BUST_SPINLOCK | ||
37 | bool | ||
38 | |||
39 | mainmenu "Linux Kernel Configuration" | 36 | mainmenu "Linux Kernel Configuration" |
40 | 37 | ||
41 | config S390 | 38 | config S390 |
@@ -181,7 +178,7 @@ config PACK_STACK | |||
181 | 178 | ||
182 | config SMALL_STACK | 179 | config SMALL_STACK |
183 | bool "Use 4kb/8kb for kernel stack instead of 8kb/16kb" | 180 | bool "Use 4kb/8kb for kernel stack instead of 8kb/16kb" |
184 | depends on PACK_STACK | 181 | depends on PACK_STACK && !LOCKDEP |
185 | help | 182 | help |
186 | If you say Y here and the compiler supports the -mkernel-backchain | 183 | If you say Y here and the compiler supports the -mkernel-backchain |
187 | option the kernel will use a smaller kernel stack size. For 31 bit | 184 | option the kernel will use a smaller kernel stack size. For 31 bit |
diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 5deb9f7544a1..6598e5268573 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile | |||
@@ -35,6 +35,9 @@ cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900) | |||
35 | cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) | 35 | cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) |
36 | cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109) | 36 | cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109) |
37 | 37 | ||
38 | #KBUILD_IMAGE is necessary for make rpm | ||
39 | KBUILD_IMAGE :=arch/s390/boot/image | ||
40 | |||
38 | # | 41 | # |
39 | # Prevent tail-call optimizations, to get clearer backtraces: | 42 | # Prevent tail-call optimizations, to get clearer backtraces: |
40 | # | 43 | # |
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index aa978978d3d1..a81881c9b297 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | EXTRA_AFLAGS := -traditional | 5 | EXTRA_AFLAGS := -traditional |
6 | 6 | ||
7 | obj-y := bitmap.o traps.o time.o process.o \ | 7 | obj-y := bitmap.o traps.o time.o process.o reset.o \ |
8 | setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ | 8 | setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ |
9 | semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o | 9 | semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o |
10 | 10 | ||
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 1eae74e72f95..a5972f1541fe 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c | |||
@@ -21,14 +21,15 @@ static DEFINE_SPINLOCK(cpcmd_lock); | |||
21 | static char cpcmd_buf[241]; | 21 | static char cpcmd_buf[241]; |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * the caller of __cpcmd has to ensure that the response buffer is below 2 GB | 24 | * __cpcmd has some restrictions over cpcmd |
25 | * - the response buffer must reside below 2GB (if any) | ||
26 | * - __cpcmd is unlocked and therefore not SMP-safe | ||
25 | */ | 27 | */ |
26 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | 28 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) |
27 | { | 29 | { |
28 | unsigned long flags, cmdlen; | 30 | unsigned cmdlen; |
29 | int return_code, return_len; | 31 | int return_code, return_len; |
30 | 32 | ||
31 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
32 | cmdlen = strlen(cmd); | 33 | cmdlen = strlen(cmd); |
33 | BUG_ON(cmdlen > 240); | 34 | BUG_ON(cmdlen > 240); |
34 | memcpy(cpcmd_buf, cmd, cmdlen); | 35 | memcpy(cpcmd_buf, cmd, cmdlen); |
@@ -74,7 +75,6 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
74 | : "+d" (reg3) : "d" (reg2) : "cc"); | 75 | : "+d" (reg3) : "d" (reg2) : "cc"); |
75 | return_code = (int) reg3; | 76 | return_code = (int) reg3; |
76 | } | 77 | } |
77 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
78 | if (response_code != NULL) | 78 | if (response_code != NULL) |
79 | *response_code = return_code; | 79 | *response_code = return_code; |
80 | return return_len; | 80 | return return_len; |
@@ -82,15 +82,18 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
82 | 82 | ||
83 | EXPORT_SYMBOL(__cpcmd); | 83 | EXPORT_SYMBOL(__cpcmd); |
84 | 84 | ||
85 | #ifdef CONFIG_64BIT | ||
86 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | 85 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code) |
87 | { | 86 | { |
88 | char *lowbuf; | 87 | char *lowbuf; |
89 | int len; | 88 | int len; |
89 | unsigned long flags; | ||
90 | 90 | ||
91 | if ((rlen == 0) || (response == NULL) | 91 | if ((rlen == 0) || (response == NULL) |
92 | || !((unsigned long)response >> 31)) | 92 | || !((unsigned long)response >> 31)) { |
93 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
93 | len = __cpcmd(cmd, response, rlen, response_code); | 94 | len = __cpcmd(cmd, response, rlen, response_code); |
95 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
96 | } | ||
94 | else { | 97 | else { |
95 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); | 98 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); |
96 | if (!lowbuf) { | 99 | if (!lowbuf) { |
@@ -98,7 +101,9 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
98 | "cpcmd: could not allocate response buffer\n"); | 101 | "cpcmd: could not allocate response buffer\n"); |
99 | return -ENOMEM; | 102 | return -ENOMEM; |
100 | } | 103 | } |
104 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
101 | len = __cpcmd(cmd, lowbuf, rlen, response_code); | 105 | len = __cpcmd(cmd, lowbuf, rlen, response_code); |
106 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
102 | memcpy(response, lowbuf, rlen); | 107 | memcpy(response, lowbuf, rlen); |
103 | kfree(lowbuf); | 108 | kfree(lowbuf); |
104 | } | 109 | } |
@@ -106,4 +111,3 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
106 | } | 111 | } |
107 | 112 | ||
108 | EXPORT_SYMBOL(cpcmd); | 113 | EXPORT_SYMBOL(cpcmd); |
109 | #endif /* CONFIG_64BIT */ | ||
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 0cf59bb7a857..8f8c802f1bcf 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S | |||
@@ -418,24 +418,6 @@ start: | |||
418 | .gotr: | 418 | .gotr: |
419 | l %r10,.tbl # EBCDIC to ASCII table | 419 | l %r10,.tbl # EBCDIC to ASCII table |
420 | tr 0(240,%r8),0(%r10) | 420 | tr 0(240,%r8),0(%r10) |
421 | stidp __LC_CPUID # Are we running on VM maybe | ||
422 | cli __LC_CPUID,0xff | ||
423 | bnz .test | ||
424 | .long 0x83300060 # diag 3,0,x'0060' - storage size | ||
425 | b .done | ||
426 | .test: | ||
427 | mvc 0x68(8),.pgmnw # set up pgm check handler | ||
428 | l %r2,.fourmeg | ||
429 | lr %r3,%r2 | ||
430 | bctr %r3,%r0 # 4M-1 | ||
431 | .loop: iske %r0,%r3 | ||
432 | ar %r3,%r2 | ||
433 | .pgmx: | ||
434 | sr %r3,%r2 | ||
435 | la %r3,1(%r3) | ||
436 | .done: | ||
437 | l %r1,.memsize | ||
438 | st %r3,ARCH_OFFSET(%r1) | ||
439 | slr %r0,%r0 | 421 | slr %r0,%r0 |
440 | st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11) | 422 | st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11) |
441 | st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11) | 423 | st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11) |
@@ -443,9 +425,6 @@ start: | |||
443 | .tbl: .long _ebcasc # translate table | 425 | .tbl: .long _ebcasc # translate table |
444 | .cmd: .long COMMAND_LINE # address of command line buffer | 426 | .cmd: .long COMMAND_LINE # address of command line buffer |
445 | .parm: .long PARMAREA | 427 | .parm: .long PARMAREA |
446 | .memsize: .long memory_size | ||
447 | .fourmeg: .long 0x00400000 # 4M | ||
448 | .pgmnw: .long 0x00080000,.pgmx | ||
449 | .lowcase: | 428 | .lowcase: |
450 | .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 | 429 | .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 |
451 | .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f | 430 | .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f |
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index 0a2c929486ab..4388b3309e0c 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S | |||
@@ -131,10 +131,11 @@ startup_continue: | |||
131 | .long init_thread_union | 131 | .long init_thread_union |
132 | .Lpmask: | 132 | .Lpmask: |
133 | .byte 0 | 133 | .byte 0 |
134 | .align 8 | 134 | .align 8 |
135 | .Lpcext:.long 0x00080000,0x80000000 | 135 | .Lpcext:.long 0x00080000,0x80000000 |
136 | .Lcr: | 136 | .Lcr: |
137 | .long 0x00 # place holder for cr0 | 137 | .long 0x00 # place holder for cr0 |
138 | .align 8 | ||
138 | .Lwaitsclp: | 139 | .Lwaitsclp: |
139 | .long 0x010a0000,0x80000000 + .Lsclph | 140 | .long 0x010a0000,0x80000000 + .Lsclph |
140 | .Lrcp: | 141 | .Lrcp: |
@@ -156,7 +157,7 @@ startup_continue: | |||
156 | slr %r4,%r4 # set start of chunk to zero | 157 | slr %r4,%r4 # set start of chunk to zero |
157 | slr %r5,%r5 # set end of chunk to zero | 158 | slr %r5,%r5 # set end of chunk to zero |
158 | slr %r6,%r6 # set access code to zero | 159 | slr %r6,%r6 # set access code to zero |
159 | la %r10, MEMORY_CHUNKS # number of chunks | 160 | la %r10,MEMORY_CHUNKS # number of chunks |
160 | .Lloop: | 161 | .Lloop: |
161 | tprot 0(%r5),0 # test protection of first byte | 162 | tprot 0(%r5),0 # test protection of first byte |
162 | ipm %r7 | 163 | ipm %r7 |
@@ -176,8 +177,6 @@ startup_continue: | |||
176 | st %r0,4(%r3) # store size of chunk | 177 | st %r0,4(%r3) # store size of chunk |
177 | st %r6,8(%r3) # store type of chunk | 178 | st %r6,8(%r3) # store type of chunk |
178 | la %r3,12(%r3) | 179 | la %r3,12(%r3) |
179 | l %r4,.Lmemsize-.LPG1(%r13) # address of variable memory_size | ||
180 | st %r5,0(%r4) # store last end to memory size | ||
181 | ahi %r10,-1 # update chunk number | 180 | ahi %r10,-1 # update chunk number |
182 | .Lchkloop: | 181 | .Lchkloop: |
183 | lr %r6,%r7 # set access code to last cc | 182 | lr %r6,%r7 # set access code to last cc |
@@ -292,7 +291,6 @@ startup_continue: | |||
292 | .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg | 291 | .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg |
293 | .Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte | 292 | .Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte |
294 | .Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c | 293 | .Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c |
295 | .Lmemsize:.long memory_size | ||
296 | .Lmchunk:.long memory_chunk | 294 | .Lmchunk:.long memory_chunk |
297 | .Lmflags:.long machine_flags | 295 | .Lmflags:.long machine_flags |
298 | .Lbss_bgn: .long __bss_start | 296 | .Lbss_bgn: .long __bss_start |
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 42f54d482441..c526279e1123 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S | |||
@@ -70,7 +70,20 @@ startup_continue: | |||
70 | sgr %r5,%r5 # set src,length and pad to zero | 70 | sgr %r5,%r5 # set src,length and pad to zero |
71 | mvcle %r2,%r4,0 # clear mem | 71 | mvcle %r2,%r4,0 # clear mem |
72 | jo .-4 # branch back, if not finish | 72 | jo .-4 # branch back, if not finish |
73 | # set program check new psw mask | ||
74 | mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) | ||
75 | larl %r1,.Lslowmemdetect # set program check address | ||
76 | stg %r1,__LC_PGM_NEW_PSW+8 | ||
77 | lghi %r1,0xc | ||
78 | diag %r0,%r1,0x260 # get memory size of virtual machine | ||
79 | cgr %r0,%r1 # different? -> old detection routine | ||
80 | jne .Lslowmemdetect | ||
81 | aghi %r1,1 # size is one more than end | ||
82 | larl %r2,memory_chunk | ||
83 | stg %r1,8(%r2) # store size of chunk | ||
84 | j .Ldonemem | ||
73 | 85 | ||
86 | .Lslowmemdetect: | ||
74 | l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word | 87 | l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word |
75 | .Lservicecall: | 88 | .Lservicecall: |
76 | stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts | 89 | stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts |
@@ -139,8 +152,6 @@ startup_continue: | |||
139 | .int 0x100000 | 152 | .int 0x100000 |
140 | 153 | ||
141 | .Lfchunk: | 154 | .Lfchunk: |
142 | # set program check new psw mask | ||
143 | mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) | ||
144 | 155 | ||
145 | # | 156 | # |
146 | # find memory chunks. | 157 | # find memory chunks. |
@@ -175,8 +186,6 @@ startup_continue: | |||
175 | stg %r0,8(%r3) # store size of chunk | 186 | stg %r0,8(%r3) # store size of chunk |
176 | st %r6,20(%r3) # store type of chunk | 187 | st %r6,20(%r3) # store type of chunk |
177 | la %r3,24(%r3) | 188 | la %r3,24(%r3) |
178 | larl %r8,memory_size | ||
179 | stg %r5,0(%r8) # store memory size | ||
180 | ahi %r10,-1 # update chunk number | 189 | ahi %r10,-1 # update chunk number |
181 | .Lchkloop: | 190 | .Lchkloop: |
182 | lr %r6,%r7 # set access code to last cc | 191 | lr %r6,%r7 # set access code to last cc |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 1f5e782b3d05..a36bea1188d9 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -13,12 +13,21 @@ | |||
13 | #include <linux/device.h> | 13 | #include <linux/device.h> |
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/reboot.h> | 15 | #include <linux/reboot.h> |
16 | #include <linux/ctype.h> | ||
16 | #include <asm/smp.h> | 17 | #include <asm/smp.h> |
17 | #include <asm/setup.h> | 18 | #include <asm/setup.h> |
18 | #include <asm/cpcmd.h> | 19 | #include <asm/cpcmd.h> |
19 | #include <asm/cio.h> | 20 | #include <asm/cio.h> |
21 | #include <asm/ebcdic.h> | ||
22 | #include <asm/reset.h> | ||
20 | 23 | ||
21 | #define IPL_PARM_BLOCK_VERSION 0 | 24 | #define IPL_PARM_BLOCK_VERSION 0 |
25 | #define LOADPARM_LEN 8 | ||
26 | |||
27 | extern char s390_readinfo_sccb[]; | ||
28 | #define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010) | ||
29 | #define SCCB_LOADPARM (&s390_readinfo_sccb[24]) | ||
30 | #define SCCB_FLAG (s390_readinfo_sccb[91]) | ||
22 | 31 | ||
23 | enum ipl_type { | 32 | enum ipl_type { |
24 | IPL_TYPE_NONE = 1, | 33 | IPL_TYPE_NONE = 1, |
@@ -289,9 +298,25 @@ static struct attribute_group ipl_fcp_attr_group = { | |||
289 | 298 | ||
290 | /* CCW ipl device attributes */ | 299 | /* CCW ipl device attributes */ |
291 | 300 | ||
301 | static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page) | ||
302 | { | ||
303 | char loadparm[LOADPARM_LEN + 1] = {}; | ||
304 | |||
305 | if (!SCCB_VALID) | ||
306 | return sprintf(page, "#unknown#\n"); | ||
307 | memcpy(loadparm, SCCB_LOADPARM, LOADPARM_LEN); | ||
308 | EBCASC(loadparm, LOADPARM_LEN); | ||
309 | strstrip(loadparm); | ||
310 | return sprintf(page, "%s\n", loadparm); | ||
311 | } | ||
312 | |||
313 | static struct subsys_attribute sys_ipl_ccw_loadparm_attr = | ||
314 | __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); | ||
315 | |||
292 | static struct attribute *ipl_ccw_attrs[] = { | 316 | static struct attribute *ipl_ccw_attrs[] = { |
293 | &sys_ipl_type_attr.attr, | 317 | &sys_ipl_type_attr.attr, |
294 | &sys_ipl_device_attr.attr, | 318 | &sys_ipl_device_attr.attr, |
319 | &sys_ipl_ccw_loadparm_attr.attr, | ||
295 | NULL, | 320 | NULL, |
296 | }; | 321 | }; |
297 | 322 | ||
@@ -348,8 +373,57 @@ static struct attribute_group reipl_fcp_attr_group = { | |||
348 | DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", | 373 | DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", |
349 | reipl_block_ccw->ipl_info.ccw.devno); | 374 | reipl_block_ccw->ipl_info.ccw.devno); |
350 | 375 | ||
376 | static void reipl_get_ascii_loadparm(char *loadparm) | ||
377 | { | ||
378 | memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param, | ||
379 | LOADPARM_LEN); | ||
380 | EBCASC(loadparm, LOADPARM_LEN); | ||
381 | loadparm[LOADPARM_LEN] = 0; | ||
382 | strstrip(loadparm); | ||
383 | } | ||
384 | |||
385 | static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page) | ||
386 | { | ||
387 | char buf[LOADPARM_LEN + 1]; | ||
388 | |||
389 | reipl_get_ascii_loadparm(buf); | ||
390 | return sprintf(page, "%s\n", buf); | ||
391 | } | ||
392 | |||
393 | static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys, | ||
394 | const char *buf, size_t len) | ||
395 | { | ||
396 | int i, lp_len; | ||
397 | |||
398 | /* ignore trailing newline */ | ||
399 | lp_len = len; | ||
400 | if ((len > 0) && (buf[len - 1] == '\n')) | ||
401 | lp_len--; | ||
402 | /* loadparm can have max 8 characters and must not start with a blank */ | ||
403 | if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' '))) | ||
404 | return -EINVAL; | ||
405 | /* loadparm can only contain "a-z,A-Z,0-9,SP,." */ | ||
406 | for (i = 0; i < lp_len; i++) { | ||
407 | if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') || | ||
408 | (buf[i] == '.')) | ||
409 | continue; | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | /* initialize loadparm with blanks */ | ||
413 | memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN); | ||
414 | /* copy and convert to ebcdic */ | ||
415 | memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len); | ||
416 | ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN); | ||
417 | return len; | ||
418 | } | ||
419 | |||
420 | static struct subsys_attribute sys_reipl_ccw_loadparm_attr = | ||
421 | __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, | ||
422 | reipl_ccw_loadparm_store); | ||
423 | |||
351 | static struct attribute *reipl_ccw_attrs[] = { | 424 | static struct attribute *reipl_ccw_attrs[] = { |
352 | &sys_reipl_ccw_device_attr.attr, | 425 | &sys_reipl_ccw_device_attr.attr, |
426 | &sys_reipl_ccw_loadparm_attr.attr, | ||
353 | NULL, | 427 | NULL, |
354 | }; | 428 | }; |
355 | 429 | ||
@@ -502,23 +576,6 @@ static struct subsys_attribute dump_type_attr = | |||
502 | 576 | ||
503 | static decl_subsys(dump, NULL, NULL); | 577 | static decl_subsys(dump, NULL, NULL); |
504 | 578 | ||
505 | #ifdef CONFIG_SMP | ||
506 | static void dump_smp_stop_all(void) | ||
507 | { | ||
508 | int cpu; | ||
509 | preempt_disable(); | ||
510 | for_each_online_cpu(cpu) { | ||
511 | if (cpu == smp_processor_id()) | ||
512 | continue; | ||
513 | while (signal_processor(cpu, sigp_stop) == sigp_busy) | ||
514 | udelay(10); | ||
515 | } | ||
516 | preempt_enable(); | ||
517 | } | ||
518 | #else | ||
519 | #define dump_smp_stop_all() do { } while (0) | ||
520 | #endif | ||
521 | |||
522 | /* | 579 | /* |
523 | * Shutdown actions section | 580 | * Shutdown actions section |
524 | */ | 581 | */ |
@@ -571,11 +628,14 @@ void do_reipl(void) | |||
571 | { | 628 | { |
572 | struct ccw_dev_id devid; | 629 | struct ccw_dev_id devid; |
573 | static char buf[100]; | 630 | static char buf[100]; |
631 | char loadparm[LOADPARM_LEN + 1]; | ||
574 | 632 | ||
575 | switch (reipl_type) { | 633 | switch (reipl_type) { |
576 | case IPL_TYPE_CCW: | 634 | case IPL_TYPE_CCW: |
635 | reipl_get_ascii_loadparm(loadparm); | ||
577 | printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n", | 636 | printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n", |
578 | reipl_block_ccw->ipl_info.ccw.devno); | 637 | reipl_block_ccw->ipl_info.ccw.devno); |
638 | printk(KERN_EMERG "loadparm = '%s'\n", loadparm); | ||
579 | break; | 639 | break; |
580 | case IPL_TYPE_FCP: | 640 | case IPL_TYPE_FCP: |
581 | printk(KERN_EMERG "reboot on fcp device:\n"); | 641 | printk(KERN_EMERG "reboot on fcp device:\n"); |
@@ -588,12 +648,19 @@ void do_reipl(void) | |||
588 | switch (reipl_method) { | 648 | switch (reipl_method) { |
589 | case IPL_METHOD_CCW_CIO: | 649 | case IPL_METHOD_CCW_CIO: |
590 | devid.devno = reipl_block_ccw->ipl_info.ccw.devno; | 650 | devid.devno = reipl_block_ccw->ipl_info.ccw.devno; |
651 | if (ipl_get_type() == IPL_TYPE_CCW && devid.devno == ipl_devno) | ||
652 | diag308(DIAG308_IPL, NULL); | ||
591 | devid.ssid = 0; | 653 | devid.ssid = 0; |
592 | reipl_ccw_dev(&devid); | 654 | reipl_ccw_dev(&devid); |
593 | break; | 655 | break; |
594 | case IPL_METHOD_CCW_VM: | 656 | case IPL_METHOD_CCW_VM: |
595 | sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno); | 657 | if (strlen(loadparm) == 0) |
596 | cpcmd(buf, NULL, 0, NULL); | 658 | sprintf(buf, "IPL %X", |
659 | reipl_block_ccw->ipl_info.ccw.devno); | ||
660 | else | ||
661 | sprintf(buf, "IPL %X LOADPARM '%s'", | ||
662 | reipl_block_ccw->ipl_info.ccw.devno, loadparm); | ||
663 | __cpcmd(buf, NULL, 0, NULL); | ||
597 | break; | 664 | break; |
598 | case IPL_METHOD_CCW_DIAG: | 665 | case IPL_METHOD_CCW_DIAG: |
599 | diag308(DIAG308_SET, reipl_block_ccw); | 666 | diag308(DIAG308_SET, reipl_block_ccw); |
@@ -607,16 +674,17 @@ void do_reipl(void) | |||
607 | diag308(DIAG308_IPL, NULL); | 674 | diag308(DIAG308_IPL, NULL); |
608 | break; | 675 | break; |
609 | case IPL_METHOD_FCP_RO_VM: | 676 | case IPL_METHOD_FCP_RO_VM: |
610 | cpcmd("IPL", NULL, 0, NULL); | 677 | __cpcmd("IPL", NULL, 0, NULL); |
611 | break; | 678 | break; |
612 | case IPL_METHOD_NONE: | 679 | case IPL_METHOD_NONE: |
613 | default: | 680 | default: |
614 | if (MACHINE_IS_VM) | 681 | if (MACHINE_IS_VM) |
615 | cpcmd("IPL", NULL, 0, NULL); | 682 | __cpcmd("IPL", NULL, 0, NULL); |
616 | diag308(DIAG308_IPL, NULL); | 683 | diag308(DIAG308_IPL, NULL); |
617 | break; | 684 | break; |
618 | } | 685 | } |
619 | panic("reipl failed!\n"); | 686 | printk(KERN_EMERG "reboot failed!\n"); |
687 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); | ||
620 | } | 688 | } |
621 | 689 | ||
622 | static void do_dump(void) | 690 | static void do_dump(void) |
@@ -639,17 +707,17 @@ static void do_dump(void) | |||
639 | 707 | ||
640 | switch (dump_method) { | 708 | switch (dump_method) { |
641 | case IPL_METHOD_CCW_CIO: | 709 | case IPL_METHOD_CCW_CIO: |
642 | dump_smp_stop_all(); | 710 | smp_send_stop(); |
643 | devid.devno = dump_block_ccw->ipl_info.ccw.devno; | 711 | devid.devno = dump_block_ccw->ipl_info.ccw.devno; |
644 | devid.ssid = 0; | 712 | devid.ssid = 0; |
645 | reipl_ccw_dev(&devid); | 713 | reipl_ccw_dev(&devid); |
646 | break; | 714 | break; |
647 | case IPL_METHOD_CCW_VM: | 715 | case IPL_METHOD_CCW_VM: |
648 | dump_smp_stop_all(); | 716 | smp_send_stop(); |
649 | sprintf(buf, "STORE STATUS"); | 717 | sprintf(buf, "STORE STATUS"); |
650 | cpcmd(buf, NULL, 0, NULL); | 718 | __cpcmd(buf, NULL, 0, NULL); |
651 | sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); | 719 | sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); |
652 | cpcmd(buf, NULL, 0, NULL); | 720 | __cpcmd(buf, NULL, 0, NULL); |
653 | break; | 721 | break; |
654 | case IPL_METHOD_CCW_DIAG: | 722 | case IPL_METHOD_CCW_DIAG: |
655 | diag308(DIAG308_SET, dump_block_ccw); | 723 | diag308(DIAG308_SET, dump_block_ccw); |
@@ -746,6 +814,17 @@ static int __init reipl_ccw_init(void) | |||
746 | reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; | 814 | reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; |
747 | reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw); | 815 | reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw); |
748 | reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; | 816 | reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; |
817 | /* check if read scp info worked and set loadparm */ | ||
818 | if (SCCB_VALID) | ||
819 | memcpy(reipl_block_ccw->ipl_info.ccw.load_param, | ||
820 | SCCB_LOADPARM, LOADPARM_LEN); | ||
821 | else | ||
822 | /* read scp info failed: set empty loadparm (EBCDIC blanks) */ | ||
823 | memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40, | ||
824 | LOADPARM_LEN); | ||
825 | /* FIXME: check for diag308_set_works when enabling diag ccw reipl */ | ||
826 | if (!MACHINE_IS_VM) | ||
827 | sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; | ||
749 | if (ipl_get_type() == IPL_TYPE_CCW) | 828 | if (ipl_get_type() == IPL_TYPE_CCW) |
750 | reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; | 829 | reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; |
751 | reipl_capabilities |= IPL_TYPE_CCW; | 830 | reipl_capabilities |= IPL_TYPE_CCW; |
@@ -827,13 +906,11 @@ static int __init dump_ccw_init(void) | |||
827 | return 0; | 906 | return 0; |
828 | } | 907 | } |
829 | 908 | ||
830 | extern char s390_readinfo_sccb[]; | ||
831 | |||
832 | static int __init dump_fcp_init(void) | 909 | static int __init dump_fcp_init(void) |
833 | { | 910 | { |
834 | int rc; | 911 | int rc; |
835 | 912 | ||
836 | if(!(s390_readinfo_sccb[91] & 0x2)) | 913 | if(!(SCCB_FLAG & 0x2) || !SCCB_VALID) |
837 | return 0; /* LDIPL DUMP is not installed */ | 914 | return 0; /* LDIPL DUMP is not installed */ |
838 | if (!diag308_set_works) | 915 | if (!diag308_set_works) |
839 | return 0; | 916 | return 0; |
@@ -931,3 +1008,53 @@ static int __init s390_ipl_init(void) | |||
931 | } | 1008 | } |
932 | 1009 | ||
933 | __initcall(s390_ipl_init); | 1010 | __initcall(s390_ipl_init); |
1011 | |||
1012 | static LIST_HEAD(rcall); | ||
1013 | static DEFINE_MUTEX(rcall_mutex); | ||
1014 | |||
1015 | void register_reset_call(struct reset_call *reset) | ||
1016 | { | ||
1017 | mutex_lock(&rcall_mutex); | ||
1018 | list_add(&reset->list, &rcall); | ||
1019 | mutex_unlock(&rcall_mutex); | ||
1020 | } | ||
1021 | EXPORT_SYMBOL_GPL(register_reset_call); | ||
1022 | |||
1023 | void unregister_reset_call(struct reset_call *reset) | ||
1024 | { | ||
1025 | mutex_lock(&rcall_mutex); | ||
1026 | list_del(&reset->list); | ||
1027 | mutex_unlock(&rcall_mutex); | ||
1028 | } | ||
1029 | EXPORT_SYMBOL_GPL(unregister_reset_call); | ||
1030 | |||
1031 | static void do_reset_calls(void) | ||
1032 | { | ||
1033 | struct reset_call *reset; | ||
1034 | |||
1035 | list_for_each_entry(reset, &rcall, list) | ||
1036 | reset->fn(); | ||
1037 | } | ||
1038 | |||
1039 | extern void reset_mcck_handler(void); | ||
1040 | |||
1041 | void s390_reset_system(void) | ||
1042 | { | ||
1043 | struct _lowcore *lc; | ||
1044 | |||
1045 | /* Stack for interrupt/machine check handler */ | ||
1046 | lc = (struct _lowcore *)(unsigned long) store_prefix(); | ||
1047 | lc->panic_stack = S390_lowcore.panic_stack; | ||
1048 | |||
1049 | /* Disable prefixing */ | ||
1050 | set_prefix(0); | ||
1051 | |||
1052 | /* Disable lowcore protection */ | ||
1053 | __ctl_clear_bit(0,28); | ||
1054 | |||
1055 | /* Set new machine check handler */ | ||
1056 | S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; | ||
1057 | S390_lowcore.mcck_new_psw.addr = | ||
1058 | PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler; | ||
1059 | do_reset_calls(); | ||
1060 | } | ||
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 60b1ea9f946b..f6d9bcc0f75b 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c | |||
@@ -1,15 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * arch/s390/kernel/machine_kexec.c | 2 | * arch/s390/kernel/machine_kexec.c |
3 | * | 3 | * |
4 | * (C) Copyright IBM Corp. 2005 | 4 | * Copyright IBM Corp. 2005,2006 |
5 | * | 5 | * |
6 | * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com> | 6 | * Author(s): Rolf Adelsberger, |
7 | * | 7 | * Heiko Carstens <heiko.carstens@de.ibm.com> |
8 | */ | ||
9 | |||
10 | /* | ||
11 | * s390_machine_kexec.c - handle the transition of Linux booting another kernel | ||
12 | * on the S390 architecture. | ||
13 | */ | 8 | */ |
14 | 9 | ||
15 | #include <linux/device.h> | 10 | #include <linux/device.h> |
@@ -22,86 +17,49 @@ | |||
22 | #include <asm/pgalloc.h> | 17 | #include <asm/pgalloc.h> |
23 | #include <asm/system.h> | 18 | #include <asm/system.h> |
24 | #include <asm/smp.h> | 19 | #include <asm/smp.h> |
20 | #include <asm/reset.h> | ||
25 | 21 | ||
26 | static void kexec_halt_all_cpus(void *); | 22 | typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long); |
27 | |||
28 | typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long); | ||
29 | 23 | ||
30 | extern const unsigned char relocate_kernel[]; | 24 | extern const unsigned char relocate_kernel[]; |
31 | extern const unsigned long long relocate_kernel_len; | 25 | extern const unsigned long long relocate_kernel_len; |
32 | 26 | ||
33 | int | 27 | int machine_kexec_prepare(struct kimage *image) |
34 | machine_kexec_prepare(struct kimage *image) | ||
35 | { | 28 | { |
36 | unsigned long reboot_code_buffer; | 29 | void *reboot_code_buffer; |
37 | 30 | ||
38 | /* We don't support anything but the default image type for now. */ | 31 | /* We don't support anything but the default image type for now. */ |
39 | if (image->type != KEXEC_TYPE_DEFAULT) | 32 | if (image->type != KEXEC_TYPE_DEFAULT) |
40 | return -EINVAL; | 33 | return -EINVAL; |
41 | 34 | ||
42 | /* Get the destination where the assembler code should be copied to.*/ | 35 | /* Get the destination where the assembler code should be copied to.*/ |
43 | reboot_code_buffer = page_to_pfn(image->control_code_page)<<PAGE_SHIFT; | 36 | reboot_code_buffer = (void *) page_to_phys(image->control_code_page); |
44 | 37 | ||
45 | /* Then copy it */ | 38 | /* Then copy it */ |
46 | memcpy((void *) reboot_code_buffer, relocate_kernel, | 39 | memcpy(reboot_code_buffer, relocate_kernel, relocate_kernel_len); |
47 | relocate_kernel_len); | ||
48 | return 0; | 40 | return 0; |
49 | } | 41 | } |
50 | 42 | ||
51 | void | 43 | void machine_kexec_cleanup(struct kimage *image) |
52 | machine_kexec_cleanup(struct kimage *image) | ||
53 | { | 44 | { |
54 | } | 45 | } |
55 | 46 | ||
56 | void | 47 | void machine_shutdown(void) |
57 | machine_shutdown(void) | ||
58 | { | 48 | { |
59 | printk(KERN_INFO "kexec: machine_shutdown called\n"); | 49 | printk(KERN_INFO "kexec: machine_shutdown called\n"); |
60 | } | 50 | } |
61 | 51 | ||
62 | NORET_TYPE void | 52 | void machine_kexec(struct kimage *image) |
63 | machine_kexec(struct kimage *image) | ||
64 | { | 53 | { |
65 | clear_all_subchannels(); | ||
66 | cio_reset_channel_paths(); | ||
67 | |||
68 | /* Disable lowcore protection */ | ||
69 | ctl_clear_bit(0,28); | ||
70 | |||
71 | on_each_cpu(kexec_halt_all_cpus, image, 0, 0); | ||
72 | for (;;); | ||
73 | } | ||
74 | |||
75 | extern void pfault_fini(void); | ||
76 | |||
77 | static void | ||
78 | kexec_halt_all_cpus(void *kernel_image) | ||
79 | { | ||
80 | static atomic_t cpuid = ATOMIC_INIT(-1); | ||
81 | int cpu; | ||
82 | struct kimage *image; | ||
83 | relocate_kernel_t data_mover; | 54 | relocate_kernel_t data_mover; |
84 | 55 | ||
85 | #ifdef CONFIG_PFAULT | 56 | smp_send_stop(); |
86 | if (MACHINE_IS_VM) | 57 | pfault_fini(); |
87 | pfault_fini(); | 58 | s390_reset_system(); |
88 | #endif | ||
89 | 59 | ||
90 | if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1) | 60 | data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page); |
91 | signal_processor(smp_processor_id(), sigp_stop); | ||
92 | |||
93 | /* Wait for all other cpus to enter stopped state */ | ||
94 | for_each_online_cpu(cpu) { | ||
95 | if (cpu == smp_processor_id()) | ||
96 | continue; | ||
97 | while (!smp_cpu_not_running(cpu)) | ||
98 | cpu_relax(); | ||
99 | } | ||
100 | |||
101 | image = (struct kimage *) kernel_image; | ||
102 | data_mover = (relocate_kernel_t) | ||
103 | (page_to_pfn(image->control_code_page) << PAGE_SHIFT); | ||
104 | 61 | ||
105 | /* Call the moving routine */ | 62 | /* Call the moving routine */ |
106 | (*data_mover) (&image->head, image->start); | 63 | (*data_mover)(&image->head, image->start); |
64 | for (;;); | ||
107 | } | 65 | } |
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index 0340477f3b08..f9434d42ce9f 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S | |||
@@ -11,19 +11,10 @@ | |||
11 | .globl do_reipl_asm | 11 | .globl do_reipl_asm |
12 | do_reipl_asm: basr %r13,0 | 12 | do_reipl_asm: basr %r13,0 |
13 | .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) | 13 | .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) |
14 | 14 | .Lpg1: # do store status of all registers | |
15 | # switch off lowcore protection | ||
16 | |||
17 | .Lpg1: stctl %c0,%c0,.Lctlsave1-.Lpg0(%r13) | ||
18 | stctl %c0,%c0,.Lctlsave2-.Lpg0(%r13) | ||
19 | ni .Lctlsave1-.Lpg0(%r13),0xef | ||
20 | lctl %c0,%c0,.Lctlsave1-.Lpg0(%r13) | ||
21 | |||
22 | # do store status of all registers | ||
23 | 15 | ||
24 | stm %r0,%r15,__LC_GPREGS_SAVE_AREA | 16 | stm %r0,%r15,__LC_GPREGS_SAVE_AREA |
25 | stctl %c0,%c15,__LC_CREGS_SAVE_AREA | 17 | stctl %c0,%c15,__LC_CREGS_SAVE_AREA |
26 | mvc __LC_CREGS_SAVE_AREA(4),.Lctlsave2-.Lpg0(%r13) | ||
27 | stam %a0,%a15,__LC_AREGS_SAVE_AREA | 18 | stam %a0,%a15,__LC_AREGS_SAVE_AREA |
28 | stpx __LC_PREFIX_SAVE_AREA | 19 | stpx __LC_PREFIX_SAVE_AREA |
29 | stckc .Lclkcmp-.Lpg0(%r13) | 20 | stckc .Lclkcmp-.Lpg0(%r13) |
@@ -56,8 +47,7 @@ do_reipl_asm: basr %r13,0 | |||
56 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 | 47 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 |
57 | jz .L003 | 48 | jz .L003 |
58 | bas %r14,.Ldisab-.Lpg0(%r13) | 49 | bas %r14,.Ldisab-.Lpg0(%r13) |
59 | .L003: spx .Lnull-.Lpg0(%r13) | 50 | .L003: st %r1,__LC_SUBCHANNEL_ID |
60 | st %r1,__LC_SUBCHANNEL_ID | ||
61 | lpsw 0 | 51 | lpsw 0 |
62 | sigp 0,0,0(6) | 52 | sigp 0,0,0(6) |
63 | .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) | 53 | .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) |
@@ -65,9 +55,6 @@ do_reipl_asm: basr %r13,0 | |||
65 | .align 8 | 55 | .align 8 |
66 | .Lclkcmp: .quad 0x0000000000000000 | 56 | .Lclkcmp: .quad 0x0000000000000000 |
67 | .Lall: .long 0xff000000 | 57 | .Lall: .long 0xff000000 |
68 | .Lnull: .long 0x00000000 | ||
69 | .Lctlsave1: .long 0x00000000 | ||
70 | .Lctlsave2: .long 0x00000000 | ||
71 | .align 8 | 58 | .align 8 |
72 | .Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 | 59 | .Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 |
73 | .Lpcnew: .long 0x00080000,0x80000000+.Lecs | 60 | .Lpcnew: .long 0x00080000,0x80000000+.Lecs |
diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S index de7435054f7c..f18ef260ca23 100644 --- a/arch/s390/kernel/reipl64.S +++ b/arch/s390/kernel/reipl64.S | |||
@@ -10,10 +10,10 @@ | |||
10 | #include <asm/lowcore.h> | 10 | #include <asm/lowcore.h> |
11 | .globl do_reipl_asm | 11 | .globl do_reipl_asm |
12 | do_reipl_asm: basr %r13,0 | 12 | do_reipl_asm: basr %r13,0 |
13 | .Lpg0: lpswe .Lnewpsw-.Lpg0(%r13) | ||
14 | .Lpg1: # do store status of all registers | ||
13 | 15 | ||
14 | # do store status of all registers | 16 | stg %r1,.Lregsave-.Lpg0(%r13) |
15 | |||
16 | .Lpg0: stg %r1,.Lregsave-.Lpg0(%r13) | ||
17 | lghi %r1,0x1000 | 17 | lghi %r1,0x1000 |
18 | stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1) | 18 | stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1) |
19 | lg %r0,.Lregsave-.Lpg0(%r13) | 19 | lg %r0,.Lregsave-.Lpg0(%r13) |
@@ -27,11 +27,7 @@ do_reipl_asm: basr %r13,0 | |||
27 | stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) | 27 | stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) |
28 | stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) | 28 | stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) |
29 | 29 | ||
30 | lpswe .Lnewpsw-.Lpg0(%r13) | 30 | lctlg %c6,%c6,.Lall-.Lpg0(%r13) |
31 | .Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13) | ||
32 | stctg %c0,%c0,.Lregsave-.Lpg0(%r13) | ||
33 | ni .Lregsave+4-.Lpg0(%r13),0xef | ||
34 | lctlg %c0,%c0,.Lregsave-.Lpg0(%r13) | ||
35 | lgr %r1,%r2 | 31 | lgr %r1,%r2 |
36 | mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) | 32 | mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) |
37 | stsch .Lschib-.Lpg0(%r13) | 33 | stsch .Lschib-.Lpg0(%r13) |
@@ -56,8 +52,7 @@ do_reipl_asm: basr %r13,0 | |||
56 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 | 52 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 |
57 | jz .L003 | 53 | jz .L003 |
58 | bas %r14,.Ldisab-.Lpg0(%r13) | 54 | bas %r14,.Ldisab-.Lpg0(%r13) |
59 | .L003: spx .Lnull-.Lpg0(%r13) | 55 | .L003: st %r1,__LC_SUBCHANNEL_ID |
60 | st %r1,__LC_SUBCHANNEL_ID | ||
61 | lhi %r1,0 # mode 0 = esa | 56 | lhi %r1,0 # mode 0 = esa |
62 | slr %r0,%r0 # set cpuid to zero | 57 | slr %r0,%r0 # set cpuid to zero |
63 | sigp %r1,%r0,0x12 # switch to esa mode | 58 | sigp %r1,%r0,0x12 # switch to esa mode |
@@ -70,7 +65,6 @@ do_reipl_asm: basr %r13,0 | |||
70 | .Lclkcmp: .quad 0x0000000000000000 | 65 | .Lclkcmp: .quad 0x0000000000000000 |
71 | .Lall: .quad 0x00000000ff000000 | 66 | .Lall: .quad 0x00000000ff000000 |
72 | .Lregsave: .quad 0x0000000000000000 | 67 | .Lregsave: .quad 0x0000000000000000 |
73 | .Lnull: .long 0x0000000000000000 | ||
74 | .align 16 | 68 | .align 16 |
75 | /* | 69 | /* |
76 | * These addresses have to be 31 bit otherwise | 70 | * These addresses have to be 31 bit otherwise |
diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S index f9899ff2e5b0..3b456b80bcee 100644 --- a/arch/s390/kernel/relocate_kernel.S +++ b/arch/s390/kernel/relocate_kernel.S | |||
@@ -26,8 +26,7 @@ | |||
26 | relocate_kernel: | 26 | relocate_kernel: |
27 | basr %r13,0 # base address | 27 | basr %r13,0 # base address |
28 | .base: | 28 | .base: |
29 | stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQ (external) | 29 | stnsm sys_msk-.base(%r13),0xfb # disable DAT |
30 | spx zero64-.base(%r13) # absolute addressing mode | ||
31 | stctl %c0,%c15,ctlregs-.base(%r13) | 30 | stctl %c0,%c15,ctlregs-.base(%r13) |
32 | stm %r0,%r15,gprregs-.base(%r13) | 31 | stm %r0,%r15,gprregs-.base(%r13) |
33 | la %r1,load_psw-.base(%r13) | 32 | la %r1,load_psw-.base(%r13) |
@@ -97,8 +96,6 @@ | |||
97 | lpsw 0 # hopefully start new kernel... | 96 | lpsw 0 # hopefully start new kernel... |
98 | 97 | ||
99 | .align 8 | 98 | .align 8 |
100 | zero64: | ||
101 | .quad 0 | ||
102 | load_psw: | 99 | load_psw: |
103 | .long 0x00080000,0x80000000 | 100 | .long 0x00080000,0x80000000 |
104 | sys_msk: | 101 | sys_msk: |
diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S index 4fb443042d9c..1f9ea2067b59 100644 --- a/arch/s390/kernel/relocate_kernel64.S +++ b/arch/s390/kernel/relocate_kernel64.S | |||
@@ -27,8 +27,7 @@ | |||
27 | relocate_kernel: | 27 | relocate_kernel: |
28 | basr %r13,0 # base address | 28 | basr %r13,0 # base address |
29 | .base: | 29 | .base: |
30 | stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQs | 30 | stnsm sys_msk-.base(%r13),0xfb # disable DAT |
31 | spx zero64-.base(%r13) # absolute addressing mode | ||
32 | stctg %c0,%c15,ctlregs-.base(%r13) | 31 | stctg %c0,%c15,ctlregs-.base(%r13) |
33 | stmg %r0,%r15,gprregs-.base(%r13) | 32 | stmg %r0,%r15,gprregs-.base(%r13) |
34 | lghi %r0,3 | 33 | lghi %r0,3 |
@@ -100,8 +99,6 @@ | |||
100 | lpsw 0 # hopefully start new kernel... | 99 | lpsw 0 # hopefully start new kernel... |
101 | 100 | ||
102 | .align 8 | 101 | .align 8 |
103 | zero64: | ||
104 | .quad 0 | ||
105 | load_psw: | 102 | load_psw: |
106 | .long 0x00080000,0x80000000 | 103 | .long 0x00080000,0x80000000 |
107 | sys_msk: | 104 | sys_msk: |
diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S new file mode 100644 index 000000000000..be8688c0665c --- /dev/null +++ b/arch/s390/kernel/reset.S | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * arch/s390/kernel/reset.S | ||
3 | * | ||
4 | * Copyright (C) IBM Corp. 2006 | ||
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #include <asm/ptrace.h> | ||
9 | #include <asm/lowcore.h> | ||
10 | |||
11 | #ifdef CONFIG_64BIT | ||
12 | |||
13 | .globl reset_mcck_handler | ||
14 | reset_mcck_handler: | ||
15 | basr %r13,0 | ||
16 | 0: lg %r15,__LC_PANIC_STACK # load panic stack | ||
17 | aghi %r15,-STACK_FRAME_OVERHEAD | ||
18 | lg %r1,s390_reset_mcck_handler-0b(%r13) | ||
19 | ltgr %r1,%r1 | ||
20 | jz 1f | ||
21 | basr %r14,%r1 | ||
22 | 1: la %r1,4095 | ||
23 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) | ||
24 | lpswe __LC_MCK_OLD_PSW | ||
25 | |||
26 | .globl s390_reset_mcck_handler | ||
27 | s390_reset_mcck_handler: | ||
28 | .quad 0 | ||
29 | |||
30 | #else /* CONFIG_64BIT */ | ||
31 | |||
32 | .globl reset_mcck_handler | ||
33 | reset_mcck_handler: | ||
34 | basr %r13,0 | ||
35 | 0: l %r15,__LC_PANIC_STACK # load panic stack | ||
36 | ahi %r15,-STACK_FRAME_OVERHEAD | ||
37 | l %r1,s390_reset_mcck_handler-0b(%r13) | ||
38 | ltr %r1,%r1 | ||
39 | jz 1f | ||
40 | basr %r14,%r1 | ||
41 | 1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA | ||
42 | lpsw __LC_MCK_OLD_PSW | ||
43 | |||
44 | .globl s390_reset_mcck_handler | ||
45 | s390_reset_mcck_handler: | ||
46 | .long 0 | ||
47 | |||
48 | #endif /* CONFIG_64BIT */ | ||
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 2aa13e8e000a..b928fecdc743 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -62,13 +62,9 @@ EXPORT_SYMBOL_GPL(uaccess); | |||
62 | unsigned int console_mode = 0; | 62 | unsigned int console_mode = 0; |
63 | unsigned int console_devno = -1; | 63 | unsigned int console_devno = -1; |
64 | unsigned int console_irq = -1; | 64 | unsigned int console_irq = -1; |
65 | unsigned long memory_size = 0; | ||
66 | unsigned long machine_flags = 0; | 65 | unsigned long machine_flags = 0; |
67 | struct { | 66 | |
68 | unsigned long addr, size, type; | 67 | struct mem_chunk memory_chunk[MEMORY_CHUNKS]; |
69 | } memory_chunk[MEMORY_CHUNKS] = { { 0 } }; | ||
70 | #define CHUNK_READ_WRITE 0 | ||
71 | #define CHUNK_READ_ONLY 1 | ||
72 | volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ | 68 | volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ |
73 | unsigned long __initdata zholes_size[MAX_NR_ZONES]; | 69 | unsigned long __initdata zholes_size[MAX_NR_ZONES]; |
74 | static unsigned long __initdata memory_end; | 70 | static unsigned long __initdata memory_end; |
@@ -229,11 +225,11 @@ static void __init conmode_default(void) | |||
229 | char *ptr; | 225 | char *ptr; |
230 | 226 | ||
231 | if (MACHINE_IS_VM) { | 227 | if (MACHINE_IS_VM) { |
232 | __cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL); | 228 | cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL); |
233 | console_devno = simple_strtoul(query_buffer + 5, NULL, 16); | 229 | console_devno = simple_strtoul(query_buffer + 5, NULL, 16); |
234 | ptr = strstr(query_buffer, "SUBCHANNEL ="); | 230 | ptr = strstr(query_buffer, "SUBCHANNEL ="); |
235 | console_irq = simple_strtoul(ptr + 13, NULL, 16); | 231 | console_irq = simple_strtoul(ptr + 13, NULL, 16); |
236 | __cpcmd("QUERY TERM", query_buffer, 1024, NULL); | 232 | cpcmd("QUERY TERM", query_buffer, 1024, NULL); |
237 | ptr = strstr(query_buffer, "CONMODE"); | 233 | ptr = strstr(query_buffer, "CONMODE"); |
238 | /* | 234 | /* |
239 | * Set the conmode to 3215 so that the device recognition | 235 | * Set the conmode to 3215 so that the device recognition |
@@ -242,7 +238,7 @@ static void __init conmode_default(void) | |||
242 | * 3215 and the 3270 driver will try to access the console | 238 | * 3215 and the 3270 driver will try to access the console |
243 | * device (3215 as console and 3270 as normal tty). | 239 | * device (3215 as console and 3270 as normal tty). |
244 | */ | 240 | */ |
245 | __cpcmd("TERM CONMODE 3215", NULL, 0, NULL); | 241 | cpcmd("TERM CONMODE 3215", NULL, 0, NULL); |
246 | if (ptr == NULL) { | 242 | if (ptr == NULL) { |
247 | #if defined(CONFIG_SCLP_CONSOLE) | 243 | #if defined(CONFIG_SCLP_CONSOLE) |
248 | SET_CONSOLE_SCLP; | 244 | SET_CONSOLE_SCLP; |
@@ -299,14 +295,14 @@ static void do_machine_restart_nonsmp(char * __unused) | |||
299 | static void do_machine_halt_nonsmp(void) | 295 | static void do_machine_halt_nonsmp(void) |
300 | { | 296 | { |
301 | if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) | 297 | if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) |
302 | cpcmd(vmhalt_cmd, NULL, 0, NULL); | 298 | __cpcmd(vmhalt_cmd, NULL, 0, NULL); |
303 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); | 299 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); |
304 | } | 300 | } |
305 | 301 | ||
306 | static void do_machine_power_off_nonsmp(void) | 302 | static void do_machine_power_off_nonsmp(void) |
307 | { | 303 | { |
308 | if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) | 304 | if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) |
309 | cpcmd(vmpoff_cmd, NULL, 0, NULL); | 305 | __cpcmd(vmpoff_cmd, NULL, 0, NULL); |
310 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); | 306 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); |
311 | } | 307 | } |
312 | 308 | ||
@@ -489,6 +485,37 @@ setup_resources(void) | |||
489 | } | 485 | } |
490 | } | 486 | } |
491 | 487 | ||
488 | static void __init setup_memory_end(void) | ||
489 | { | ||
490 | unsigned long real_size, memory_size; | ||
491 | unsigned long max_mem, max_phys; | ||
492 | int i; | ||
493 | |||
494 | memory_size = real_size = 0; | ||
495 | max_phys = VMALLOC_END - VMALLOC_MIN_SIZE; | ||
496 | memory_end &= PAGE_MASK; | ||
497 | |||
498 | max_mem = memory_end ? min(max_phys, memory_end) : max_phys; | ||
499 | |||
500 | for (i = 0; i < MEMORY_CHUNKS; i++) { | ||
501 | struct mem_chunk *chunk = &memory_chunk[i]; | ||
502 | |||
503 | real_size = max(real_size, chunk->addr + chunk->size); | ||
504 | if (chunk->addr >= max_mem) { | ||
505 | memset(chunk, 0, sizeof(*chunk)); | ||
506 | continue; | ||
507 | } | ||
508 | if (chunk->addr + chunk->size > max_mem) | ||
509 | chunk->size = max_mem - chunk->addr; | ||
510 | memory_size = max(memory_size, chunk->addr + chunk->size); | ||
511 | } | ||
512 | if (!memory_end) | ||
513 | memory_end = memory_size; | ||
514 | if (real_size > memory_end) | ||
515 | printk("More memory detected than supported. Unused: %luk\n", | ||
516 | (real_size - memory_end) >> 10); | ||
517 | } | ||
518 | |||
492 | static void __init | 519 | static void __init |
493 | setup_memory(void) | 520 | setup_memory(void) |
494 | { | 521 | { |
@@ -645,8 +672,6 @@ setup_arch(char **cmdline_p) | |||
645 | init_mm.end_data = (unsigned long) &_edata; | 672 | init_mm.end_data = (unsigned long) &_edata; |
646 | init_mm.brk = (unsigned long) &_end; | 673 | init_mm.brk = (unsigned long) &_end; |
647 | 674 | ||
648 | memory_end = memory_size; | ||
649 | |||
650 | if (MACHINE_HAS_MVCOS) | 675 | if (MACHINE_HAS_MVCOS) |
651 | memcpy(&uaccess, &uaccess_mvcos, sizeof(uaccess)); | 676 | memcpy(&uaccess, &uaccess_mvcos, sizeof(uaccess)); |
652 | else | 677 | else |
@@ -654,20 +679,7 @@ setup_arch(char **cmdline_p) | |||
654 | 679 | ||
655 | parse_early_param(); | 680 | parse_early_param(); |
656 | 681 | ||
657 | #ifndef CONFIG_64BIT | 682 | setup_memory_end(); |
658 | memory_end &= ~0x400000UL; | ||
659 | |||
660 | /* | ||
661 | * We need some free virtual space to be able to do vmalloc. | ||
662 | * On a machine with 2GB memory we make sure that we have at | ||
663 | * least 128 MB free space for vmalloc. | ||
664 | */ | ||
665 | if (memory_end > 1920*1024*1024) | ||
666 | memory_end = 1920*1024*1024; | ||
667 | #else /* CONFIG_64BIT */ | ||
668 | memory_end &= ~0x200000UL; | ||
669 | #endif /* CONFIG_64BIT */ | ||
670 | |||
671 | setup_memory(); | 683 | setup_memory(); |
672 | setup_resources(); | 684 | setup_resources(); |
673 | setup_lowcore(); | 685 | setup_lowcore(); |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 62822245f9be..19090f7d4f51 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -230,18 +230,37 @@ static inline void do_store_status(void) | |||
230 | } | 230 | } |
231 | } | 231 | } |
232 | 232 | ||
233 | static inline void do_wait_for_stop(void) | ||
234 | { | ||
235 | int cpu; | ||
236 | |||
237 | /* Wait for all other cpus to enter stopped state */ | ||
238 | for_each_online_cpu(cpu) { | ||
239 | if (cpu == smp_processor_id()) | ||
240 | continue; | ||
241 | while(!smp_cpu_not_running(cpu)) | ||
242 | cpu_relax(); | ||
243 | } | ||
244 | } | ||
245 | |||
233 | /* | 246 | /* |
234 | * this function sends a 'stop' sigp to all other CPUs in the system. | 247 | * this function sends a 'stop' sigp to all other CPUs in the system. |
235 | * it goes straight through. | 248 | * it goes straight through. |
236 | */ | 249 | */ |
237 | void smp_send_stop(void) | 250 | void smp_send_stop(void) |
238 | { | 251 | { |
252 | /* Disable all interrupts/machine checks */ | ||
253 | __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK); | ||
254 | |||
239 | /* write magic number to zero page (absolute 0) */ | 255 | /* write magic number to zero page (absolute 0) */ |
240 | lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; | 256 | lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; |
241 | 257 | ||
242 | /* stop other processors. */ | 258 | /* stop other processors. */ |
243 | do_send_stop(); | 259 | do_send_stop(); |
244 | 260 | ||
261 | /* wait until other processors are stopped */ | ||
262 | do_wait_for_stop(); | ||
263 | |||
245 | /* store status of other processors. */ | 264 | /* store status of other processors. */ |
246 | do_store_status(); | 265 | do_store_status(); |
247 | } | 266 | } |
@@ -250,88 +269,28 @@ void smp_send_stop(void) | |||
250 | * Reboot, halt and power_off routines for SMP. | 269 | * Reboot, halt and power_off routines for SMP. |
251 | */ | 270 | */ |
252 | 271 | ||
253 | static void do_machine_restart(void * __unused) | ||
254 | { | ||
255 | int cpu; | ||
256 | static atomic_t cpuid = ATOMIC_INIT(-1); | ||
257 | |||
258 | if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1) | ||
259 | signal_processor(smp_processor_id(), sigp_stop); | ||
260 | |||
261 | /* Wait for all other cpus to enter stopped state */ | ||
262 | for_each_online_cpu(cpu) { | ||
263 | if (cpu == smp_processor_id()) | ||
264 | continue; | ||
265 | while(!smp_cpu_not_running(cpu)) | ||
266 | cpu_relax(); | ||
267 | } | ||
268 | |||
269 | /* Store status of other cpus. */ | ||
270 | do_store_status(); | ||
271 | |||
272 | /* | ||
273 | * Finally call reipl. Because we waited for all other | ||
274 | * cpus to enter this function we know that they do | ||
275 | * not hold any s390irq-locks (the cpus have been | ||
276 | * interrupted by an external interrupt and s390irq | ||
277 | * locks are always held disabled). | ||
278 | */ | ||
279 | do_reipl(); | ||
280 | } | ||
281 | |||
282 | void machine_restart_smp(char * __unused) | 272 | void machine_restart_smp(char * __unused) |
283 | { | 273 | { |
284 | on_each_cpu(do_machine_restart, NULL, 0, 0); | 274 | smp_send_stop(); |
285 | } | 275 | do_reipl(); |
286 | |||
287 | static void do_wait_for_stop(void) | ||
288 | { | ||
289 | unsigned long cr[16]; | ||
290 | |||
291 | __ctl_store(cr, 0, 15); | ||
292 | cr[0] &= ~0xffff; | ||
293 | cr[6] = 0; | ||
294 | __ctl_load(cr, 0, 15); | ||
295 | for (;;) | ||
296 | enabled_wait(); | ||
297 | } | ||
298 | |||
299 | static void do_machine_halt(void * __unused) | ||
300 | { | ||
301 | static atomic_t cpuid = ATOMIC_INIT(-1); | ||
302 | |||
303 | if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) == -1) { | ||
304 | smp_send_stop(); | ||
305 | if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) | ||
306 | cpcmd(vmhalt_cmd, NULL, 0, NULL); | ||
307 | signal_processor(smp_processor_id(), | ||
308 | sigp_stop_and_store_status); | ||
309 | } | ||
310 | do_wait_for_stop(); | ||
311 | } | 276 | } |
312 | 277 | ||
313 | void machine_halt_smp(void) | 278 | void machine_halt_smp(void) |
314 | { | 279 | { |
315 | on_each_cpu(do_machine_halt, NULL, 0, 0); | 280 | smp_send_stop(); |
316 | } | 281 | if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) |
317 | 282 | __cpcmd(vmhalt_cmd, NULL, 0, NULL); | |
318 | static void do_machine_power_off(void * __unused) | 283 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); |
319 | { | 284 | for (;;); |
320 | static atomic_t cpuid = ATOMIC_INIT(-1); | ||
321 | |||
322 | if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) == -1) { | ||
323 | smp_send_stop(); | ||
324 | if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) | ||
325 | cpcmd(vmpoff_cmd, NULL, 0, NULL); | ||
326 | signal_processor(smp_processor_id(), | ||
327 | sigp_stop_and_store_status); | ||
328 | } | ||
329 | do_wait_for_stop(); | ||
330 | } | 285 | } |
331 | 286 | ||
332 | void machine_power_off_smp(void) | 287 | void machine_power_off_smp(void) |
333 | { | 288 | { |
334 | on_each_cpu(do_machine_power_off, NULL, 0, 0); | 289 | smp_send_stop(); |
290 | if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) | ||
291 | __cpcmd(vmpoff_cmd, NULL, 0, NULL); | ||
292 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); | ||
293 | for (;;); | ||
335 | } | 294 | } |
336 | 295 | ||
337 | /* | 296 | /* |
@@ -501,8 +460,6 @@ __init smp_count_cpus(void) | |||
501 | */ | 460 | */ |
502 | extern void init_cpu_timer(void); | 461 | extern void init_cpu_timer(void); |
503 | extern void init_cpu_vtimer(void); | 462 | extern void init_cpu_vtimer(void); |
504 | extern int pfault_init(void); | ||
505 | extern void pfault_fini(void); | ||
506 | 463 | ||
507 | int __devinit start_secondary(void *cpuvoid) | 464 | int __devinit start_secondary(void *cpuvoid) |
508 | { | 465 | { |
@@ -514,11 +471,9 @@ int __devinit start_secondary(void *cpuvoid) | |||
514 | #ifdef CONFIG_VIRT_TIMER | 471 | #ifdef CONFIG_VIRT_TIMER |
515 | init_cpu_vtimer(); | 472 | init_cpu_vtimer(); |
516 | #endif | 473 | #endif |
517 | #ifdef CONFIG_PFAULT | ||
518 | /* Enable pfault pseudo page faults on this cpu. */ | 474 | /* Enable pfault pseudo page faults on this cpu. */ |
519 | if (MACHINE_IS_VM) | 475 | pfault_init(); |
520 | pfault_init(); | 476 | |
521 | #endif | ||
522 | /* Mark this cpu as online */ | 477 | /* Mark this cpu as online */ |
523 | cpu_set(smp_processor_id(), cpu_online_map); | 478 | cpu_set(smp_processor_id(), cpu_online_map); |
524 | /* Switch on interrupts */ | 479 | /* Switch on interrupts */ |
@@ -708,11 +663,8 @@ __cpu_disable(void) | |||
708 | } | 663 | } |
709 | cpu_clear(cpu, cpu_online_map); | 664 | cpu_clear(cpu, cpu_online_map); |
710 | 665 | ||
711 | #ifdef CONFIG_PFAULT | ||
712 | /* Disable pfault pseudo page faults on this cpu. */ | 666 | /* Disable pfault pseudo page faults on this cpu. */ |
713 | if (MACHINE_IS_VM) | 667 | pfault_fini(); |
714 | pfault_fini(); | ||
715 | #endif | ||
716 | 668 | ||
717 | memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals)); | 669 | memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals)); |
718 | memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals)); | 670 | memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals)); |
@@ -860,4 +812,3 @@ EXPORT_SYMBOL(smp_ctl_clear_bit); | |||
860 | EXPORT_SYMBOL(smp_call_function); | 812 | EXPORT_SYMBOL(smp_call_function); |
861 | EXPORT_SYMBOL(smp_get_cpu); | 813 | EXPORT_SYMBOL(smp_get_cpu); |
862 | EXPORT_SYMBOL(smp_put_cpu); | 814 | EXPORT_SYMBOL(smp_put_cpu); |
863 | |||
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 92ecffbc8d82..3cbb0dcf1f1d 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -58,12 +58,6 @@ int sysctl_userprocess_debug = 0; | |||
58 | 58 | ||
59 | extern pgm_check_handler_t do_protection_exception; | 59 | extern pgm_check_handler_t do_protection_exception; |
60 | extern pgm_check_handler_t do_dat_exception; | 60 | extern pgm_check_handler_t do_dat_exception; |
61 | #ifdef CONFIG_PFAULT | ||
62 | extern int pfault_init(void); | ||
63 | extern void pfault_fini(void); | ||
64 | extern void pfault_interrupt(__u16 error_code); | ||
65 | static ext_int_info_t ext_int_pfault; | ||
66 | #endif | ||
67 | extern pgm_check_handler_t do_monitor_call; | 61 | extern pgm_check_handler_t do_monitor_call; |
68 | 62 | ||
69 | #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) | 63 | #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) |
@@ -135,7 +129,7 @@ __show_trace(unsigned long sp, unsigned long low, unsigned long high) | |||
135 | } | 129 | } |
136 | } | 130 | } |
137 | 131 | ||
138 | void show_trace(struct task_struct *task, unsigned long * stack) | 132 | void show_trace(struct task_struct *task, unsigned long *stack) |
139 | { | 133 | { |
140 | register unsigned long __r15 asm ("15"); | 134 | register unsigned long __r15 asm ("15"); |
141 | unsigned long sp; | 135 | unsigned long sp; |
@@ -157,6 +151,9 @@ void show_trace(struct task_struct *task, unsigned long * stack) | |||
157 | __show_trace(sp, S390_lowcore.thread_info, | 151 | __show_trace(sp, S390_lowcore.thread_info, |
158 | S390_lowcore.thread_info + THREAD_SIZE); | 152 | S390_lowcore.thread_info + THREAD_SIZE); |
159 | printk("\n"); | 153 | printk("\n"); |
154 | if (!task) | ||
155 | task = current; | ||
156 | debug_show_held_locks(task); | ||
160 | } | 157 | } |
161 | 158 | ||
162 | void show_stack(struct task_struct *task, unsigned long *sp) | 159 | void show_stack(struct task_struct *task, unsigned long *sp) |
@@ -739,22 +736,5 @@ void __init trap_init(void) | |||
739 | pgm_check_table[0x1C] = &space_switch_exception; | 736 | pgm_check_table[0x1C] = &space_switch_exception; |
740 | pgm_check_table[0x1D] = &hfp_sqrt_exception; | 737 | pgm_check_table[0x1D] = &hfp_sqrt_exception; |
741 | pgm_check_table[0x40] = &do_monitor_call; | 738 | pgm_check_table[0x40] = &do_monitor_call; |
742 | 739 | pfault_irq_init(); | |
743 | if (MACHINE_IS_VM) { | ||
744 | #ifdef CONFIG_PFAULT | ||
745 | /* | ||
746 | * Try to get pfault pseudo page faults going. | ||
747 | */ | ||
748 | if (register_early_external_interrupt(0x2603, pfault_interrupt, | ||
749 | &ext_int_pfault) != 0) | ||
750 | panic("Couldn't request external interrupt 0x2603"); | ||
751 | |||
752 | if (pfault_init() == 0) | ||
753 | return; | ||
754 | |||
755 | /* Tough luck, no pfault. */ | ||
756 | unregister_early_external_interrupt(0x2603, pfault_interrupt, | ||
757 | &ext_int_pfault); | ||
758 | #endif | ||
759 | } | ||
760 | } | 740 | } |
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index b0cfa6c4883d..b5f94cf3bde8 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | EXTRA_AFLAGS := -traditional | 5 | EXTRA_AFLAGS := -traditional |
6 | 6 | ||
7 | lib-y += delay.o string.o uaccess_std.o | 7 | lib-y += delay.o string.o uaccess_std.o uaccess_pt.o |
8 | lib-$(CONFIG_32BIT) += div64.o | 8 | lib-$(CONFIG_32BIT) += div64.o |
9 | lib-$(CONFIG_64BIT) += uaccess_mvcos.o | 9 | lib-$(CONFIG_64BIT) += uaccess_mvcos.o |
10 | lib-$(CONFIG_SMP) += spinlock.o | 10 | lib-$(CONFIG_SMP) += spinlock.o |
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c index 121b2935a422..f9a23d57eb79 100644 --- a/arch/s390/lib/uaccess_mvcos.c +++ b/arch/s390/lib/uaccess_mvcos.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #define SLR "slgr" | 27 | #define SLR "slgr" |
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | extern size_t copy_from_user_std(size_t, const void __user *, void *); | ||
31 | extern size_t copy_to_user_std(size_t, void __user *, const void *); | ||
32 | |||
30 | size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) | 33 | size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) |
31 | { | 34 | { |
32 | register unsigned long reg0 asm("0") = 0x81UL; | 35 | register unsigned long reg0 asm("0") = 0x81UL; |
@@ -66,6 +69,13 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) | |||
66 | return size; | 69 | return size; |
67 | } | 70 | } |
68 | 71 | ||
72 | size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x) | ||
73 | { | ||
74 | if (size <= 256) | ||
75 | return copy_from_user_std(size, ptr, x); | ||
76 | return copy_from_user_mvcos(size, ptr, x); | ||
77 | } | ||
78 | |||
69 | size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) | 79 | size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) |
70 | { | 80 | { |
71 | register unsigned long reg0 asm("0") = 0x810000UL; | 81 | register unsigned long reg0 asm("0") = 0x810000UL; |
@@ -95,6 +105,13 @@ size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) | |||
95 | return size; | 105 | return size; |
96 | } | 106 | } |
97 | 107 | ||
108 | size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, const void *x) | ||
109 | { | ||
110 | if (size <= 256) | ||
111 | return copy_to_user_std(size, ptr, x); | ||
112 | return copy_to_user_mvcos(size, ptr, x); | ||
113 | } | ||
114 | |||
98 | size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from) | 115 | size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from) |
99 | { | 116 | { |
100 | register unsigned long reg0 asm("0") = 0x810081UL; | 117 | register unsigned long reg0 asm("0") = 0x810081UL; |
@@ -145,18 +162,16 @@ size_t clear_user_mvcos(size_t size, void __user *to) | |||
145 | return size; | 162 | return size; |
146 | } | 163 | } |
147 | 164 | ||
148 | extern size_t copy_from_user_std_small(size_t, const void __user *, void *); | ||
149 | extern size_t copy_to_user_std_small(size_t, void __user *, const void *); | ||
150 | extern size_t strnlen_user_std(size_t, const char __user *); | 165 | extern size_t strnlen_user_std(size_t, const char __user *); |
151 | extern size_t strncpy_from_user_std(size_t, const char __user *, char *); | 166 | extern size_t strncpy_from_user_std(size_t, const char __user *, char *); |
152 | extern int futex_atomic_op(int, int __user *, int, int *); | 167 | extern int futex_atomic_op(int, int __user *, int, int *); |
153 | extern int futex_atomic_cmpxchg(int __user *, int, int); | 168 | extern int futex_atomic_cmpxchg(int __user *, int, int); |
154 | 169 | ||
155 | struct uaccess_ops uaccess_mvcos = { | 170 | struct uaccess_ops uaccess_mvcos = { |
156 | .copy_from_user = copy_from_user_mvcos, | 171 | .copy_from_user = copy_from_user_mvcos_check, |
157 | .copy_from_user_small = copy_from_user_std_small, | 172 | .copy_from_user_small = copy_from_user_std, |
158 | .copy_to_user = copy_to_user_mvcos, | 173 | .copy_to_user = copy_to_user_mvcos_check, |
159 | .copy_to_user_small = copy_to_user_std_small, | 174 | .copy_to_user_small = copy_to_user_std, |
160 | .copy_in_user = copy_in_user_mvcos, | 175 | .copy_in_user = copy_in_user_mvcos, |
161 | .clear_user = clear_user_mvcos, | 176 | .clear_user = clear_user_mvcos, |
162 | .strnlen_user = strnlen_user_std, | 177 | .strnlen_user = strnlen_user_std, |
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c new file mode 100644 index 000000000000..8741bdc09299 --- /dev/null +++ b/arch/s390/lib/uaccess_pt.c | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * arch/s390/lib/uaccess_pt.c | ||
3 | * | ||
4 | * User access functions based on page table walks. | ||
5 | * | ||
6 | * Copyright IBM Corp. 2006 | ||
7 | * Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com) | ||
8 | */ | ||
9 | |||
10 | #include <linux/errno.h> | ||
11 | #include <asm/uaccess.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <asm/futex.h> | ||
14 | |||
15 | static inline int __handle_fault(struct mm_struct *mm, unsigned long address, | ||
16 | int write_access) | ||
17 | { | ||
18 | struct vm_area_struct *vma; | ||
19 | int ret = -EFAULT; | ||
20 | |||
21 | down_read(&mm->mmap_sem); | ||
22 | vma = find_vma(mm, address); | ||
23 | if (unlikely(!vma)) | ||
24 | goto out; | ||
25 | if (unlikely(vma->vm_start > address)) { | ||
26 | if (!(vma->vm_flags & VM_GROWSDOWN)) | ||
27 | goto out; | ||
28 | if (expand_stack(vma, address)) | ||
29 | goto out; | ||
30 | } | ||
31 | |||
32 | if (!write_access) { | ||
33 | /* page not present, check vm flags */ | ||
34 | if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) | ||
35 | goto out; | ||
36 | } else { | ||
37 | if (!(vma->vm_flags & VM_WRITE)) | ||
38 | goto out; | ||
39 | } | ||
40 | |||
41 | survive: | ||
42 | switch (handle_mm_fault(mm, vma, address, write_access)) { | ||
43 | case VM_FAULT_MINOR: | ||
44 | current->min_flt++; | ||
45 | break; | ||
46 | case VM_FAULT_MAJOR: | ||
47 | current->maj_flt++; | ||
48 | break; | ||
49 | case VM_FAULT_SIGBUS: | ||
50 | goto out_sigbus; | ||
51 | case VM_FAULT_OOM: | ||
52 | goto out_of_memory; | ||
53 | default: | ||
54 | BUG(); | ||
55 | } | ||
56 | ret = 0; | ||
57 | out: | ||
58 | up_read(&mm->mmap_sem); | ||
59 | return ret; | ||
60 | |||
61 | out_of_memory: | ||
62 | up_read(&mm->mmap_sem); | ||
63 | if (current->pid == 1) { | ||
64 | yield(); | ||
65 | goto survive; | ||
66 | } | ||
67 | printk("VM: killing process %s\n", current->comm); | ||
68 | return ret; | ||
69 | |||
70 | out_sigbus: | ||
71 | up_read(&mm->mmap_sem); | ||
72 | current->thread.prot_addr = address; | ||
73 | current->thread.trap_no = 0x11; | ||
74 | force_sig(SIGBUS, current); | ||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, | ||
79 | size_t n, int write_user) | ||
80 | { | ||
81 | struct mm_struct *mm = current->mm; | ||
82 | unsigned long offset, pfn, done, size; | ||
83 | pgd_t *pgd; | ||
84 | pmd_t *pmd; | ||
85 | pte_t *pte; | ||
86 | void *from, *to; | ||
87 | |||
88 | done = 0; | ||
89 | retry: | ||
90 | spin_lock(&mm->page_table_lock); | ||
91 | do { | ||
92 | pgd = pgd_offset(mm, uaddr); | ||
93 | if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) | ||
94 | goto fault; | ||
95 | |||
96 | pmd = pmd_offset(pgd, uaddr); | ||
97 | if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) | ||
98 | goto fault; | ||
99 | |||
100 | pte = pte_offset_map(pmd, uaddr); | ||
101 | if (!pte || !pte_present(*pte) || | ||
102 | (write_user && !pte_write(*pte))) | ||
103 | goto fault; | ||
104 | |||
105 | pfn = pte_pfn(*pte); | ||
106 | if (!pfn_valid(pfn)) | ||
107 | goto out; | ||
108 | |||
109 | offset = uaddr & (PAGE_SIZE - 1); | ||
110 | size = min(n - done, PAGE_SIZE - offset); | ||
111 | if (write_user) { | ||
112 | to = (void *)((pfn << PAGE_SHIFT) + offset); | ||
113 | from = kptr + done; | ||
114 | } else { | ||
115 | from = (void *)((pfn << PAGE_SHIFT) + offset); | ||
116 | to = kptr + done; | ||
117 | } | ||
118 | memcpy(to, from, size); | ||
119 | done += size; | ||
120 | uaddr += size; | ||
121 | } while (done < n); | ||
122 | out: | ||
123 | spin_unlock(&mm->page_table_lock); | ||
124 | return n - done; | ||
125 | fault: | ||
126 | spin_unlock(&mm->page_table_lock); | ||
127 | if (__handle_fault(mm, uaddr, write_user)) | ||
128 | return n - done; | ||
129 | goto retry; | ||
130 | } | ||
131 | |||
132 | size_t copy_from_user_pt(size_t n, const void __user *from, void *to) | ||
133 | { | ||
134 | size_t rc; | ||
135 | |||
136 | if (segment_eq(get_fs(), KERNEL_DS)) { | ||
137 | memcpy(to, (void __kernel __force *) from, n); | ||
138 | return 0; | ||
139 | } | ||
140 | rc = __user_copy_pt((unsigned long) from, to, n, 0); | ||
141 | if (unlikely(rc)) | ||
142 | memset(to + n - rc, 0, rc); | ||
143 | return rc; | ||
144 | } | ||
145 | |||
146 | size_t copy_to_user_pt(size_t n, void __user *to, const void *from) | ||
147 | { | ||
148 | if (segment_eq(get_fs(), KERNEL_DS)) { | ||
149 | memcpy((void __kernel __force *) to, from, n); | ||
150 | return 0; | ||
151 | } | ||
152 | return __user_copy_pt((unsigned long) to, (void *) from, n, 1); | ||
153 | } | ||
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c index f44f0078b354..2d549ed2e113 100644 --- a/arch/s390/lib/uaccess_std.c +++ b/arch/s390/lib/uaccess_std.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #define SLR "slgr" | 28 | #define SLR "slgr" |
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | extern size_t copy_from_user_pt(size_t n, const void __user *from, void *to); | ||
32 | extern size_t copy_to_user_pt(size_t n, void __user *to, const void *from); | ||
33 | |||
31 | size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) | 34 | size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) |
32 | { | 35 | { |
33 | unsigned long tmp1, tmp2; | 36 | unsigned long tmp1, tmp2; |
@@ -69,34 +72,11 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) | |||
69 | return size; | 72 | return size; |
70 | } | 73 | } |
71 | 74 | ||
72 | size_t copy_from_user_std_small(size_t size, const void __user *ptr, void *x) | 75 | size_t copy_from_user_std_check(size_t size, const void __user *ptr, void *x) |
73 | { | 76 | { |
74 | unsigned long tmp1, tmp2; | 77 | if (size <= 1024) |
75 | 78 | return copy_from_user_std(size, ptr, x); | |
76 | tmp1 = 0UL; | 79 | return copy_from_user_pt(size, ptr, x); |
77 | asm volatile( | ||
78 | "0: mvcp 0(%0,%2),0(%1),%3\n" | ||
79 | " "SLR" %0,%0\n" | ||
80 | " j 5f\n" | ||
81 | "1: la %4,255(%1)\n" /* %4 = ptr + 255 */ | ||
82 | " "LHI" %3,-4096\n" | ||
83 | " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */ | ||
84 | " "SLR" %4,%1\n" | ||
85 | " "CLR" %0,%4\n" /* copy crosses next page boundary? */ | ||
86 | " jnh 5f\n" | ||
87 | "2: mvcp 0(%4,%2),0(%1),%3\n" | ||
88 | " "SLR" %0,%4\n" | ||
89 | " "ALR" %2,%4\n" | ||
90 | "3:"LHI" %4,-1\n" | ||
91 | " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */ | ||
92 | " bras %3,4f\n" | ||
93 | " xc 0(1,%2),0(%2)\n" | ||
94 | "4: ex %4,0(%3)\n" | ||
95 | "5:\n" | ||
96 | EX_TABLE(0b,1b) EX_TABLE(2b,3b) | ||
97 | : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) | ||
98 | : : "cc", "memory"); | ||
99 | return size; | ||
100 | } | 80 | } |
101 | 81 | ||
102 | size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) | 82 | size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) |
@@ -130,28 +110,11 @@ size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) | |||
130 | return size; | 110 | return size; |
131 | } | 111 | } |
132 | 112 | ||
133 | size_t copy_to_user_std_small(size_t size, void __user *ptr, const void *x) | 113 | size_t copy_to_user_std_check(size_t size, void __user *ptr, const void *x) |
134 | { | 114 | { |
135 | unsigned long tmp1, tmp2; | 115 | if (size <= 1024) |
136 | 116 | return copy_to_user_std(size, ptr, x); | |
137 | tmp1 = 0UL; | 117 | return copy_to_user_pt(size, ptr, x); |
138 | asm volatile( | ||
139 | "0: mvcs 0(%0,%1),0(%2),%3\n" | ||
140 | " "SLR" %0,%0\n" | ||
141 | " j 3f\n" | ||
142 | "1: la %4,255(%1)\n" /* ptr + 255 */ | ||
143 | " "LHI" %3,-4096\n" | ||
144 | " nr %4,%3\n" /* (ptr + 255) & -4096UL */ | ||
145 | " "SLR" %4,%1\n" | ||
146 | " "CLR" %0,%4\n" /* copy crosses next page boundary? */ | ||
147 | " jnh 3f\n" | ||
148 | "2: mvcs 0(%4,%1),0(%2),%3\n" | ||
149 | " "SLR" %0,%4\n" | ||
150 | "3:\n" | ||
151 | EX_TABLE(0b,1b) EX_TABLE(2b,3b) | ||
152 | : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) | ||
153 | : : "cc", "memory"); | ||
154 | return size; | ||
155 | } | 118 | } |
156 | 119 | ||
157 | size_t copy_in_user_std(size_t size, void __user *to, const void __user *from) | 120 | size_t copy_in_user_std(size_t size, void __user *to, const void __user *from) |
@@ -343,10 +306,10 @@ int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval) | |||
343 | } | 306 | } |
344 | 307 | ||
345 | struct uaccess_ops uaccess_std = { | 308 | struct uaccess_ops uaccess_std = { |
346 | .copy_from_user = copy_from_user_std, | 309 | .copy_from_user = copy_from_user_std_check, |
347 | .copy_from_user_small = copy_from_user_std_small, | 310 | .copy_from_user_small = copy_from_user_std, |
348 | .copy_to_user = copy_to_user_std, | 311 | .copy_to_user = copy_to_user_std_check, |
349 | .copy_to_user_small = copy_to_user_std_small, | 312 | .copy_to_user_small = copy_to_user_std, |
350 | .copy_in_user = copy_in_user_std, | 313 | .copy_in_user = copy_in_user_std, |
351 | .clear_user = clear_user_std, | 314 | .clear_user = clear_user_std, |
352 | .strnlen_user = strnlen_user_std, | 315 | .strnlen_user = strnlen_user_std, |
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 226275d5c4f6..9e9bc48463a5 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c | |||
@@ -14,12 +14,13 @@ | |||
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/bootmem.h> | 16 | #include <linux/bootmem.h> |
17 | #include <linux/ctype.h> | ||
17 | #include <asm/page.h> | 18 | #include <asm/page.h> |
18 | #include <asm/ebcdic.h> | 19 | #include <asm/ebcdic.h> |
19 | #include <asm/errno.h> | 20 | #include <asm/errno.h> |
20 | #include <asm/extmem.h> | 21 | #include <asm/extmem.h> |
21 | #include <asm/cpcmd.h> | 22 | #include <asm/cpcmd.h> |
22 | #include <linux/ctype.h> | 23 | #include <asm/setup.h> |
23 | 24 | ||
24 | #define DCSS_DEBUG /* Debug messages on/off */ | 25 | #define DCSS_DEBUG /* Debug messages on/off */ |
25 | 26 | ||
@@ -77,15 +78,11 @@ struct dcss_segment { | |||
77 | int segcnt; | 78 | int segcnt; |
78 | }; | 79 | }; |
79 | 80 | ||
80 | static DEFINE_SPINLOCK(dcss_lock); | 81 | static DEFINE_MUTEX(dcss_lock); |
81 | static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list); | 82 | static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list); |
82 | static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", | 83 | static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", |
83 | "EW/EN-MIXED" }; | 84 | "EW/EN-MIXED" }; |
84 | 85 | ||
85 | extern struct { | ||
86 | unsigned long addr, size, type; | ||
87 | } memory_chunk[MEMORY_CHUNKS]; | ||
88 | |||
89 | /* | 86 | /* |
90 | * Create the 8 bytes, ebcdic VM segment name from | 87 | * Create the 8 bytes, ebcdic VM segment name from |
91 | * an ascii name. | 88 | * an ascii name. |
@@ -117,7 +114,7 @@ segment_by_name (char *name) | |||
117 | struct list_head *l; | 114 | struct list_head *l; |
118 | struct dcss_segment *tmp, *retval = NULL; | 115 | struct dcss_segment *tmp, *retval = NULL; |
119 | 116 | ||
120 | assert_spin_locked(&dcss_lock); | 117 | BUG_ON(!mutex_is_locked(&dcss_lock)); |
121 | dcss_mkname (name, dcss_name); | 118 | dcss_mkname (name, dcss_name); |
122 | list_for_each (l, &dcss_list) { | 119 | list_for_each (l, &dcss_list) { |
123 | tmp = list_entry (l, struct dcss_segment, list); | 120 | tmp = list_entry (l, struct dcss_segment, list); |
@@ -249,8 +246,8 @@ segment_overlaps_storage(struct dcss_segment *seg) | |||
249 | { | 246 | { |
250 | int i; | 247 | int i; |
251 | 248 | ||
252 | for (i=0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { | 249 | for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { |
253 | if (memory_chunk[i].type != 0) | 250 | if (memory_chunk[i].type != CHUNK_READ_WRITE) |
254 | continue; | 251 | continue; |
255 | if ((memory_chunk[i].addr >> 20) > (seg->end >> 20)) | 252 | if ((memory_chunk[i].addr >> 20) > (seg->end >> 20)) |
256 | continue; | 253 | continue; |
@@ -272,7 +269,7 @@ segment_overlaps_others (struct dcss_segment *seg) | |||
272 | struct list_head *l; | 269 | struct list_head *l; |
273 | struct dcss_segment *tmp; | 270 | struct dcss_segment *tmp; |
274 | 271 | ||
275 | assert_spin_locked(&dcss_lock); | 272 | BUG_ON(!mutex_is_locked(&dcss_lock)); |
276 | list_for_each(l, &dcss_list) { | 273 | list_for_each(l, &dcss_list) { |
277 | tmp = list_entry(l, struct dcss_segment, list); | 274 | tmp = list_entry(l, struct dcss_segment, list); |
278 | if ((tmp->start_addr >> 20) > (seg->end >> 20)) | 275 | if ((tmp->start_addr >> 20) > (seg->end >> 20)) |
@@ -429,7 +426,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, | |||
429 | if (!MACHINE_IS_VM) | 426 | if (!MACHINE_IS_VM) |
430 | return -ENOSYS; | 427 | return -ENOSYS; |
431 | 428 | ||
432 | spin_lock (&dcss_lock); | 429 | mutex_lock(&dcss_lock); |
433 | seg = segment_by_name (name); | 430 | seg = segment_by_name (name); |
434 | if (seg == NULL) | 431 | if (seg == NULL) |
435 | rc = __segment_load (name, do_nonshared, addr, end); | 432 | rc = __segment_load (name, do_nonshared, addr, end); |
@@ -444,7 +441,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, | |||
444 | rc = -EPERM; | 441 | rc = -EPERM; |
445 | } | 442 | } |
446 | } | 443 | } |
447 | spin_unlock (&dcss_lock); | 444 | mutex_unlock(&dcss_lock); |
448 | return rc; | 445 | return rc; |
449 | } | 446 | } |
450 | 447 | ||
@@ -467,7 +464,7 @@ segment_modify_shared (char *name, int do_nonshared) | |||
467 | unsigned long dummy; | 464 | unsigned long dummy; |
468 | int dcss_command, rc, diag_cc; | 465 | int dcss_command, rc, diag_cc; |
469 | 466 | ||
470 | spin_lock (&dcss_lock); | 467 | mutex_lock(&dcss_lock); |
471 | seg = segment_by_name (name); | 468 | seg = segment_by_name (name); |
472 | if (seg == NULL) { | 469 | if (seg == NULL) { |
473 | rc = -EINVAL; | 470 | rc = -EINVAL; |
@@ -508,7 +505,7 @@ segment_modify_shared (char *name, int do_nonshared) | |||
508 | &dummy, &dummy); | 505 | &dummy, &dummy); |
509 | kfree(seg); | 506 | kfree(seg); |
510 | out_unlock: | 507 | out_unlock: |
511 | spin_unlock(&dcss_lock); | 508 | mutex_unlock(&dcss_lock); |
512 | return rc; | 509 | return rc; |
513 | } | 510 | } |
514 | 511 | ||
@@ -526,7 +523,7 @@ segment_unload(char *name) | |||
526 | if (!MACHINE_IS_VM) | 523 | if (!MACHINE_IS_VM) |
527 | return; | 524 | return; |
528 | 525 | ||
529 | spin_lock(&dcss_lock); | 526 | mutex_lock(&dcss_lock); |
530 | seg = segment_by_name (name); | 527 | seg = segment_by_name (name); |
531 | if (seg == NULL) { | 528 | if (seg == NULL) { |
532 | PRINT_ERR ("could not find segment %s in segment_unload, " | 529 | PRINT_ERR ("could not find segment %s in segment_unload, " |
@@ -540,7 +537,7 @@ segment_unload(char *name) | |||
540 | kfree(seg); | 537 | kfree(seg); |
541 | } | 538 | } |
542 | out_unlock: | 539 | out_unlock: |
543 | spin_unlock(&dcss_lock); | 540 | mutex_unlock(&dcss_lock); |
544 | } | 541 | } |
545 | 542 | ||
546 | /* | 543 | /* |
@@ -559,12 +556,13 @@ segment_save(char *name) | |||
559 | if (!MACHINE_IS_VM) | 556 | if (!MACHINE_IS_VM) |
560 | return; | 557 | return; |
561 | 558 | ||
562 | spin_lock(&dcss_lock); | 559 | mutex_lock(&dcss_lock); |
563 | seg = segment_by_name (name); | 560 | seg = segment_by_name (name); |
564 | 561 | ||
565 | if (seg == NULL) { | 562 | if (seg == NULL) { |
566 | PRINT_ERR ("could not find segment %s in segment_save, please report to linux390@de.ibm.com\n",name); | 563 | PRINT_ERR("could not find segment %s in segment_save, please " |
567 | return; | 564 | "report to linux390@de.ibm.com\n", name); |
565 | goto out; | ||
568 | } | 566 | } |
569 | 567 | ||
570 | startpfn = seg->start_addr >> PAGE_SHIFT; | 568 | startpfn = seg->start_addr >> PAGE_SHIFT; |
@@ -591,7 +589,7 @@ segment_save(char *name) | |||
591 | goto out; | 589 | goto out; |
592 | } | 590 | } |
593 | out: | 591 | out: |
594 | spin_unlock(&dcss_lock); | 592 | mutex_unlock(&dcss_lock); |
595 | } | 593 | } |
596 | 594 | ||
597 | EXPORT_SYMBOL(segment_load); | 595 | EXPORT_SYMBOL(segment_load); |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 1c323bbfda91..cd85e34d8703 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
32 | #include <asm/pgtable.h> | 32 | #include <asm/pgtable.h> |
33 | #include <asm/kdebug.h> | 33 | #include <asm/kdebug.h> |
34 | #include <asm/s390_ext.h> | ||
34 | 35 | ||
35 | #ifndef CONFIG_64BIT | 36 | #ifndef CONFIG_64BIT |
36 | #define __FAIL_ADDR_MASK 0x7ffff000 | 37 | #define __FAIL_ADDR_MASK 0x7ffff000 |
@@ -394,6 +395,7 @@ void do_dat_exception(struct pt_regs *regs, unsigned long error_code) | |||
394 | /* | 395 | /* |
395 | * 'pfault' pseudo page faults routines. | 396 | * 'pfault' pseudo page faults routines. |
396 | */ | 397 | */ |
398 | static ext_int_info_t ext_int_pfault; | ||
397 | static int pfault_disable = 0; | 399 | static int pfault_disable = 0; |
398 | 400 | ||
399 | static int __init nopfault(char *str) | 401 | static int __init nopfault(char *str) |
@@ -422,7 +424,7 @@ int pfault_init(void) | |||
422 | __PF_RES_FIELD }; | 424 | __PF_RES_FIELD }; |
423 | int rc; | 425 | int rc; |
424 | 426 | ||
425 | if (pfault_disable) | 427 | if (!MACHINE_IS_VM || pfault_disable) |
426 | return -1; | 428 | return -1; |
427 | asm volatile( | 429 | asm volatile( |
428 | " diag %1,%0,0x258\n" | 430 | " diag %1,%0,0x258\n" |
@@ -440,7 +442,7 @@ void pfault_fini(void) | |||
440 | pfault_refbk_t refbk = | 442 | pfault_refbk_t refbk = |
441 | { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL }; | 443 | { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL }; |
442 | 444 | ||
443 | if (pfault_disable) | 445 | if (!MACHINE_IS_VM || pfault_disable) |
444 | return; | 446 | return; |
445 | __ctl_clear_bit(0,9); | 447 | __ctl_clear_bit(0,9); |
446 | asm volatile( | 448 | asm volatile( |
@@ -500,5 +502,25 @@ pfault_interrupt(__u16 error_code) | |||
500 | set_tsk_need_resched(tsk); | 502 | set_tsk_need_resched(tsk); |
501 | } | 503 | } |
502 | } | 504 | } |
503 | #endif | ||
504 | 505 | ||
506 | void __init pfault_irq_init(void) | ||
507 | { | ||
508 | if (!MACHINE_IS_VM) | ||
509 | return; | ||
510 | |||
511 | /* | ||
512 | * Try to get pfault pseudo page faults going. | ||
513 | */ | ||
514 | if (register_early_external_interrupt(0x2603, pfault_interrupt, | ||
515 | &ext_int_pfault) != 0) | ||
516 | panic("Couldn't request external interrupt 0x2603"); | ||
517 | |||
518 | if (pfault_init() == 0) | ||
519 | return; | ||
520 | |||
521 | /* Tough luck, no pfault. */ | ||
522 | pfault_disable = 1; | ||
523 | unregister_early_external_interrupt(0x2603, pfault_interrupt, | ||
524 | &ext_int_pfault); | ||
525 | } | ||
526 | #endif | ||
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ad8b537ad47b..24f922f12783 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -855,39 +855,6 @@ config TANBAC_TB0219 | |||
855 | depends TANBAC_TB022X | 855 | depends TANBAC_TB022X |
856 | select GPIO_VR41XX | 856 | select GPIO_VR41XX |
857 | 857 | ||
858 | menu "Ftape, the floppy tape device driver" | ||
859 | |||
860 | config FTAPE | ||
861 | tristate "Ftape (QIC-80/Travan) support" | ||
862 | depends on BROKEN_ON_SMP && (ALPHA || X86) | ||
863 | ---help--- | ||
864 | If you have a tape drive that is connected to your floppy | ||
865 | controller, say Y here. | ||
866 | |||
867 | Some tape drives (like the Seagate "Tape Store 3200" or the Iomega | ||
868 | "Ditto 3200" or the Exabyte "Eagle TR-3") come with a "high speed" | ||
869 | controller of their own. These drives (and their companion | ||
870 | controllers) are also supported if you say Y here. | ||
871 | |||
872 | If you have a special controller (such as the CMS FC-10, FC-20, | ||
873 | Mountain Mach-II, or any controller that is based on the Intel 82078 | ||
874 | FDC like the high speed controllers by Seagate and Exabyte and | ||
875 | Iomega's "Ditto Dash") you must configure it by selecting the | ||
876 | appropriate entries from the "Floppy tape controllers" sub-menu | ||
877 | below and possibly modify the default values for the IRQ and DMA | ||
878 | channel and the IO base in ftape's configuration menu. | ||
879 | |||
880 | If you want to use your floppy tape drive on a PCI-bus based system, | ||
881 | please read the file <file:drivers/char/ftape/README.PCI>. | ||
882 | |||
883 | The ftape kernel driver is also available as a runtime loadable | ||
884 | module. To compile this driver as a module, choose M here: the | ||
885 | module will be called ftape. | ||
886 | |||
887 | source "drivers/char/ftape/Kconfig" | ||
888 | |||
889 | endmenu | ||
890 | |||
891 | source "drivers/char/agp/Kconfig" | 858 | source "drivers/char/agp/Kconfig" |
892 | 859 | ||
893 | source "drivers/char/drm/Kconfig" | 860 | source "drivers/char/drm/Kconfig" |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 777cad045094..b1fcdab90947 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -78,7 +78,6 @@ obj-$(CONFIG_TOSHIBA) += toshiba.o | |||
78 | obj-$(CONFIG_I8K) += i8k.o | 78 | obj-$(CONFIG_I8K) += i8k.o |
79 | obj-$(CONFIG_DS1620) += ds1620.o | 79 | obj-$(CONFIG_DS1620) += ds1620.o |
80 | obj-$(CONFIG_HW_RANDOM) += hw_random/ | 80 | obj-$(CONFIG_HW_RANDOM) += hw_random/ |
81 | obj-$(CONFIG_FTAPE) += ftape/ | ||
82 | obj-$(CONFIG_COBALT_LCD) += lcd.o | 81 | obj-$(CONFIG_COBALT_LCD) += lcd.o |
83 | obj-$(CONFIG_PPDEV) += ppdev.o | 82 | obj-$(CONFIG_PPDEV) += ppdev.o |
84 | obj-$(CONFIG_NWBUTTON) += nwbutton.o | 83 | obj-$(CONFIG_NWBUTTON) += nwbutton.o |
diff --git a/drivers/char/ftape/Kconfig b/drivers/char/ftape/Kconfig deleted file mode 100644 index 0d65189a7ae8..000000000000 --- a/drivers/char/ftape/Kconfig +++ /dev/null | |||
@@ -1,330 +0,0 @@ | |||
1 | # | ||
2 | # Ftape configuration | ||
3 | # | ||
4 | config ZFTAPE | ||
5 | tristate "Zftape, the VFS interface" | ||
6 | depends on FTAPE | ||
7 | ---help--- | ||
8 | Normally, you want to say Y or M. DON'T say N here or you | ||
9 | WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE. | ||
10 | |||
11 | The ftape module itself no longer contains the routines necessary | ||
12 | to interface with the kernel VFS layer (i.e. to actually write data | ||
13 | to and read data from the tape drive). Instead the file system | ||
14 | interface (i.e. the hardware independent part of the driver) has | ||
15 | been moved to a separate module. | ||
16 | |||
17 | To compile this driver as a module, choose M here: the | ||
18 | module will be called zftape. | ||
19 | |||
20 | Regardless of whether you say Y or M here, an additional runtime | ||
21 | loadable module called `zft-compressor' which contains code to | ||
22 | support user transparent on-the-fly compression based on Ross | ||
23 | William's lzrw3 algorithm will be produced. If you have enabled the | ||
24 | kernel module loader (i.e. have said Y to "Kernel module loader | ||
25 | support", above) then `zft-compressor' will be loaded | ||
26 | automatically by zftape when needed. | ||
27 | |||
28 | Despite its name, zftape does NOT use compression by default. | ||
29 | |||
30 | config ZFT_DFLT_BLK_SZ | ||
31 | int "Default block size" | ||
32 | depends on ZFTAPE | ||
33 | default "10240" | ||
34 | ---help--- | ||
35 | If unsure leave this at its default value, i.e. 10240. Note that | ||
36 | you specify only the default block size here. The block size can be | ||
37 | changed at run time using the MTSETBLK tape operation with the | ||
38 | MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the | ||
39 | shell command line). | ||
40 | |||
41 | The probably most striking difference between zftape and previous | ||
42 | versions of ftape is the fact that all data must be written or read | ||
43 | in multiples of a fixed block size. The block size defaults to | ||
44 | 10240 which is what GNU tar uses. The values for the block size | ||
45 | should be either 1 or multiples of 1024 up to a maximum value of | ||
46 | 63488 (i.e. 62 K). If you specify `1' then zftape's builtin | ||
47 | compression will be disabled. | ||
48 | |||
49 | Reasonable values are `10240' (GNU tar's default block size), | ||
50 | `5120' (afio's default block size), `32768' (default block size some | ||
51 | backup programs assume for SCSI tape drives) or `1' (no restriction | ||
52 | on block size, but disables builtin compression). | ||
53 | |||
54 | comment "The compressor will be built as a module only!" | ||
55 | depends on FTAPE && ZFTAPE | ||
56 | |||
57 | config ZFT_COMPRESSOR | ||
58 | tristate | ||
59 | depends on FTAPE!=n && ZFTAPE!=n | ||
60 | default m | ||
61 | |||
62 | config FT_NR_BUFFERS | ||
63 | int "Number of ftape buffers (EXPERIMENTAL)" | ||
64 | depends on FTAPE && EXPERIMENTAL | ||
65 | default "3" | ||
66 | help | ||
67 | Please leave this at `3' unless you REALLY know what you are doing. | ||
68 | It is not necessary to change this value. Values below 3 make the | ||
69 | proper use of ftape impossible, values greater than 3 are a waste of | ||
70 | memory. You can change the amount of DMA memory used by ftape at | ||
71 | runtime with "mt -f /dev/qft0 setdrvbuffer #NUMBUFFERS". Each buffer | ||
72 | wastes 32 KB of memory. Please note that this memory cannot be | ||
73 | swapped out. | ||
74 | |||
75 | config FT_PROC_FS | ||
76 | bool "Enable procfs status report (+2kb)" | ||
77 | depends on FTAPE && PROC_FS | ||
78 | ---help--- | ||
79 | Optional. Saying Y will result in creation of a directory | ||
80 | `/proc/ftape' under the /proc file system. The files can be viewed | ||
81 | with your favorite pager (i.e. use "more /proc/ftape/history" or | ||
82 | "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The | ||
83 | file will contain some status information about the inserted | ||
84 | cartridge, the kernel driver, your tape drive, the floppy disk | ||
85 | controller and the error history for the most recent use of the | ||
86 | kernel driver. Saying Y will enlarge the size of the ftape driver | ||
87 | by approximately 2 KB. | ||
88 | |||
89 | WARNING: When compiling ftape as a module (i.e. saying M to "Floppy | ||
90 | tape drive") it is dangerous to use ftape's /proc file system | ||
91 | interface. Accessing `/proc/ftape' while the module is unloaded will | ||
92 | result in a kernel Oops. This cannot be fixed from inside ftape. | ||
93 | |||
94 | choice | ||
95 | prompt "Debugging output" | ||
96 | depends on FTAPE | ||
97 | default FT_NORMAL_DEBUG | ||
98 | |||
99 | config FT_NORMAL_DEBUG | ||
100 | bool "Normal" | ||
101 | ---help--- | ||
102 | This option controls the amount of debugging output the ftape driver | ||
103 | is ABLE to produce; it does not increase or diminish the debugging | ||
104 | level itself. If unsure, leave this at its default setting, | ||
105 | i.e. choose "Normal". | ||
106 | |||
107 | Ftape can print lots of debugging messages to the system console | ||
108 | resp. kernel log files. Reducing the amount of possible debugging | ||
109 | output reduces the size of the kernel module by some KB, so it might | ||
110 | be a good idea to use "None" for emergency boot floppies. | ||
111 | |||
112 | If you want to save memory then the following strategy is | ||
113 | recommended: leave this option at its default setting "Normal" until | ||
114 | you know that the driver works as expected, afterwards reconfigure | ||
115 | the kernel, this time specifying "Reduced" or "None" and recompile | ||
116 | and install the kernel as usual. Note that choosing "Excessive" | ||
117 | debugging output does not increase the amount of debugging output | ||
118 | printed to the console but only makes it possible to produce | ||
119 | "Excessive" debugging output. | ||
120 | |||
121 | Please read <file:Documentation/ftape.txt> for a short description | ||
122 | how to control the amount of debugging output. | ||
123 | |||
124 | config FT_FULL_DEBUG | ||
125 | bool "Excessive" | ||
126 | help | ||
127 | Extremely verbose output for driver debugging purposes. | ||
128 | |||
129 | config FT_NO_TRACE | ||
130 | bool "Reduced" | ||
131 | help | ||
132 | Reduced tape driver debugging output. | ||
133 | |||
134 | config FT_NO_TRACE_AT_ALL | ||
135 | bool "None" | ||
136 | help | ||
137 | Suppress all debugging output from the tape drive. | ||
138 | |||
139 | endchoice | ||
140 | |||
141 | comment "Hardware configuration" | ||
142 | depends on FTAPE | ||
143 | |||
144 | choice | ||
145 | prompt "Floppy tape controllers" | ||
146 | depends on FTAPE | ||
147 | default FT_STD_FDC | ||
148 | |||
149 | config FT_STD_FDC | ||
150 | bool "Standard" | ||
151 | ---help--- | ||
152 | Only change this setting if you have a special controller. If you | ||
153 | didn't plug any add-on card into your computer system but just | ||
154 | plugged the floppy tape cable into the already existing floppy drive | ||
155 | controller then you don't want to change the default setting, | ||
156 | i.e. choose "Standard". | ||
157 | |||
158 | Choose "MACH-2" if you have a Mountain Mach-2 controller. | ||
159 | Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20 | ||
160 | controller. | ||
161 | Choose "Alt/82078" if you have another controller that is located at | ||
162 | an IO base address different from the standard floppy drive | ||
163 | controller's base address of `0x3f0', or uses an IRQ (interrupt) | ||
164 | channel different from `6', or a DMA channel different from | ||
165 | `2'. This is necessary for any controller card that is based on | ||
166 | Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high | ||
167 | speed" controllers. | ||
168 | |||
169 | If you choose something other than "Standard" then please make | ||
170 | sure that the settings for the IO base address and the IRQ and DMA | ||
171 | channel in the configuration menus below are correct. Use the manual | ||
172 | of your tape drive to determine the correct settings! | ||
173 | |||
174 | If you are already successfully using your tape drive with another | ||
175 | operating system then you definitely should use the same settings | ||
176 | for the IO base, the IRQ and DMA channel that have proven to work | ||
177 | with that other OS. | ||
178 | |||
179 | Note that this menu lets you specify only the default setting for | ||
180 | the hardware setup. The hardware configuration can be changed at | ||
181 | boot time (when ftape is compiled into the kernel, i.e. if you | ||
182 | have said Y to "Floppy tape drive") or module load time (i.e. if you | ||
183 | have said M to "Floppy tape drive"). | ||
184 | |||
185 | Please read also the file <file:Documentation/ftape.txt> which | ||
186 | contains a short description of the parameters that can be set at | ||
187 | boot or load time. If you want to use your floppy tape drive on a | ||
188 | PCI-bus based system, please read the file | ||
189 | <file:drivers/char/ftape/README.PCI>. | ||
190 | |||
191 | config FT_MACH2 | ||
192 | bool "MACH-2" | ||
193 | |||
194 | config FT_PROBE_FC10 | ||
195 | bool "FC-10/FC-20" | ||
196 | |||
197 | config FT_ALT_FDC | ||
198 | bool "Alt/82078" | ||
199 | |||
200 | endchoice | ||
201 | |||
202 | comment "Consult the manuals of your tape drive for the correct settings!" | ||
203 | depends on FTAPE && !FT_STD_FDC | ||
204 | |||
205 | config FT_FDC_BASE | ||
206 | hex "IO base of the floppy disk controller" | ||
207 | depends on FTAPE && !FT_STD_FDC | ||
208 | default "0" | ||
209 | ---help--- | ||
210 | You don't need to specify a value if the following default | ||
211 | settings for the base IO address are correct: | ||
212 | <<< MACH-2 : 0x1E0 >>> | ||
213 | <<< FC-10/FC-20: 0x180 >>> | ||
214 | <<< Secondary : 0x370 >>> | ||
215 | Secondary refers to a secondary FDC controller like the "high speed" | ||
216 | controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. | ||
217 | Please make sure that the setting for the IO base address | ||
218 | specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR | ||
219 | CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already | ||
220 | successfully using the tape drive with another operating system then | ||
221 | you definitely should use the same settings for the IO base that has | ||
222 | proven to work with that other OS. | ||
223 | |||
224 | Note that this menu lets you specify only the default setting for | ||
225 | the IO base. The hardware configuration can be changed at boot time | ||
226 | (when ftape is compiled into the kernel, i.e. if you specified Y to | ||
227 | "Floppy tape drive") or module load time (i.e. if you have said M to | ||
228 | "Floppy tape drive"). | ||
229 | |||
230 | Please read also the file <file:Documentation/ftape.txt> which | ||
231 | contains a short description of the parameters that can be set at | ||
232 | boot or load time. | ||
233 | |||
234 | config FT_FDC_IRQ | ||
235 | int "IRQ channel of the floppy disk controller" | ||
236 | depends on FTAPE && !FT_STD_FDC | ||
237 | default "0" | ||
238 | ---help--- | ||
239 | You don't need to specify a value if the following default | ||
240 | settings for the interrupt channel are correct: | ||
241 | <<< MACH-2 : 6 >>> | ||
242 | <<< FC-10/FC-20: 9 >>> | ||
243 | <<< Secondary : 6 >>> | ||
244 | Secondary refers to secondary a FDC controller like the "high speed" | ||
245 | controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. | ||
246 | Please make sure that the setting for the IO base address | ||
247 | specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR | ||
248 | CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already | ||
249 | successfully using the tape drive with another operating system then | ||
250 | you definitely should use the same settings for the IO base that has | ||
251 | proven to work with that other OS. | ||
252 | |||
253 | Note that this menu lets you specify only the default setting for | ||
254 | the IRQ channel. The hardware configuration can be changed at boot | ||
255 | time (when ftape is compiled into the kernel, i.e. if you said Y to | ||
256 | "Floppy tape drive") or module load time (i.e. if you said M to | ||
257 | "Floppy tape drive"). | ||
258 | |||
259 | Please read also the file <file:Documentation/ftape.txt> which | ||
260 | contains a short description of the parameters that can be set at | ||
261 | boot or load time. | ||
262 | |||
263 | config FT_FDC_DMA | ||
264 | int "DMA channel of the floppy disk controller" | ||
265 | depends on FTAPE && !FT_STD_FDC | ||
266 | default "0" | ||
267 | ---help--- | ||
268 | You don't need to specify a value if the following default | ||
269 | settings for the DMA channel are correct: | ||
270 | <<< MACH-2 : 2 >>> | ||
271 | <<< FC-10/FC-20: 3 >>> | ||
272 | <<< Secondary : 2 >>> | ||
273 | Secondary refers to a secondary FDC controller like the "high speed" | ||
274 | controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. | ||
275 | Please make sure that the setting for the IO base address | ||
276 | specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR | ||
277 | CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already | ||
278 | successfully using the tape drive with another operating system then | ||
279 | you definitely should use the same settings for the IO base that has | ||
280 | proven to work with that other OS. | ||
281 | |||
282 | Note that this menu lets you specify only the default setting for | ||
283 | the DMA channel. The hardware configuration can be changed at boot | ||
284 | time (when ftape is compiled into the kernel, i.e. if you said Y to | ||
285 | "Floppy tape drive") or module load time (i.e. if you said M to | ||
286 | "Floppy tape drive"). | ||
287 | |||
288 | Please read also the file <file:Documentation/ftape.txt> which | ||
289 | contains a short description of the parameters that can be set at | ||
290 | boot or load time. | ||
291 | |||
292 | config FT_FDC_THR | ||
293 | int "Default FIFO threshold (EXPERIMENTAL)" | ||
294 | depends on FTAPE && EXPERIMENTAL | ||
295 | default "8" | ||
296 | help | ||
297 | Set the FIFO threshold of the FDC. If this is higher the DMA | ||
298 | controller may serve the FDC after a higher latency time. If this is | ||
299 | lower, fewer DMA transfers occur leading to less bus contention. | ||
300 | You may try to tune this if ftape annoys you with "reduced data | ||
301 | rate because of excessive overrun errors" messages. However, this | ||
302 | doesn't seem to have too much effect. | ||
303 | |||
304 | If unsure, don't touch the initial value, i.e. leave it at "8". | ||
305 | |||
306 | config FT_FDC_MAX_RATE | ||
307 | int "Maximal data rate to use (EXPERIMENTAL)" | ||
308 | depends on FTAPE && EXPERIMENTAL | ||
309 | default "2000" | ||
310 | ---help--- | ||
311 | With some motherboard/FDC combinations ftape will not be able to | ||
312 | run your FDC/tape drive combination at the highest available | ||
313 | speed. If this is the case you'll encounter "reduced data rate | ||
314 | because of excessive overrun errors" messages and lots of retries | ||
315 | before ftape finally decides to reduce the data rate. | ||
316 | |||
317 | In this case it might be desirable to tell ftape beforehand that | ||
318 | it need not try to run the tape drive at the highest available | ||
319 | speed. If unsure, leave this disabled, i.e. leave it at 2000 | ||
320 | bits/sec. | ||
321 | |||
322 | config FT_ALPHA_CLOCK | ||
323 | int "CPU clock frequency of your DEC Alpha" if ALPHA | ||
324 | depends on FTAPE | ||
325 | default "0" | ||
326 | help | ||
327 | On some DEC Alpha machines the CPU clock frequency cannot be | ||
328 | determined automatically, so you need to specify it here ONLY if | ||
329 | running a DEC Alpha, otherwise this setting has no effect. | ||
330 | |||
diff --git a/drivers/char/ftape/Makefile b/drivers/char/ftape/Makefile deleted file mode 100644 index 0e67d2f8b7ec..000000000000 --- a/drivers/char/ftape/Makefile +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | # | ||
2 | # Copyright (C) 1997 Claus 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/Makefile,v $ | ||
19 | # $Revision: 1.4 $ | ||
20 | # $Date: 1997/10/05 19:17:56 $ | ||
21 | # | ||
22 | # Makefile for the QIC-40/80/3010/3020 floppy-tape driver for | ||
23 | # Linux. | ||
24 | # | ||
25 | |||
26 | obj-$(CONFIG_FTAPE) += lowlevel/ | ||
27 | obj-$(CONFIG_ZFTAPE) += zftape/ | ||
28 | obj-$(CONFIG_ZFT_COMPRESSOR) += compressor/ | ||
diff --git a/drivers/char/ftape/README.PCI b/drivers/char/ftape/README.PCI deleted file mode 100644 index 18de159d36e0..000000000000 --- a/drivers/char/ftape/README.PCI +++ /dev/null | |||
@@ -1,81 +0,0 @@ | |||
1 | Some notes for ftape users with PCI motherboards: | ||
2 | ================================================= | ||
3 | |||
4 | The problem: | ||
5 | ------------ | ||
6 | |||
7 | There have been some problem reports from people using PCI-bus based | ||
8 | systems getting overrun errors. | ||
9 | I wasn't able to reproduce these until I ran ftape on a Intel Plato | ||
10 | (Premiere PCI II) motherboard with bios version 1.00.08AX1. | ||
11 | It turned out that if GAT (Guaranteed Access Timing) is enabled (?) | ||
12 | ftape gets a lot of overrun errors. | ||
13 | The problem disappears when disabling GAT in the bios. | ||
14 | Note that Intel removed this setting (permanently disabled) from the | ||
15 | 1.00.10AX1 bios ! | ||
16 | |||
17 | It looks like that if GAT is enabled there are often large periods | ||
18 | (greater than 120 us !??) on the ISA bus that the DMA controller cannot | ||
19 | service the floppy disk controller. | ||
20 | I cannot imagine this being acceptable in a decent PCI implementation. | ||
21 | Maybe this is a `feature' of the chipset. I can only speculate why | ||
22 | Intel choose to remove the option from the latest Bios... | ||
23 | |||
24 | The lesson of this all is that there may be other motherboard | ||
25 | implementations having the same of similar problems. | ||
26 | If you experience a lot of overrun errors during a backup to tape, | ||
27 | see if there is some setting in the Bios that may influence the | ||
28 | bus timing. | ||
29 | |||
30 | I judge this a hardware problem and not a limitation of ftape ;-) | ||
31 | My DOS backup software seems to be suffering from the same problems | ||
32 | and even refuses to run at 1 Mbps ! | ||
33 | Ftape will reduce the data-rate from 1 Mbps to 500 Kbps if the number | ||
34 | of overrun errors on a track exceeds a threshold. | ||
35 | |||
36 | |||
37 | Possible solutions: | ||
38 | ------------------- | ||
39 | |||
40 | Some of the problems were solved by upgrading the (flash) bios. | ||
41 | Other suggest that it has to do with the FDC being on the PCI | ||
42 | bus, but that is not the case with the Intel Premiere II boards. | ||
43 | [If upgrading the bios doesn't solve the problem you could try | ||
44 | a floppy disk controller on the isa-bus]. | ||
45 | |||
46 | Here is a list of systems and recommended BIOS settings: | ||
47 | |||
48 | |||
49 | Intel Premiere PCI (Revenge): | ||
50 | |||
51 | Bios version 1.00.09.AF2 is reported to work. | ||
52 | |||
53 | |||
54 | |||
55 | Intel Premiere PCI II (Plato): | ||
56 | |||
57 | Bios version 1.00.10.AX1 and version 11 beta are ok. | ||
58 | If using version 1.00.08.AX1, GAT must be disabled ! | ||
59 | |||
60 | |||
61 | |||
62 | ASUS PCI/I-SP3G: | ||
63 | |||
64 | Preferred settings: ISA-GAT-mode : disabled | ||
65 | DMA-linebuffer-mode : standard | ||
66 | ISA-masterbuffer-mode : standard | ||
67 | |||
68 | |||
69 | DELL Dimension XPS P90 | ||
70 | |||
71 | Bios version A2 is reported to be broken, while bios version A5 works. | ||
72 | You can get a flash bios upgrade from http://www.dell.com | ||
73 | |||
74 | |||
75 | To see if you're having the GAT problem, try making a backup | ||
76 | under DOS. If it's very slow and often repositions you're | ||
77 | probably having this problem. | ||
78 | |||
79 | --//-- | ||
80 | LocalWords: ftape PCI bios GAT ISA DMA chipset Mbps Kbps FDC isa AF ok ASUS | ||
81 | LocalWords: SP linebuffer masterbuffer XPS http www com | ||
diff --git a/drivers/char/ftape/RELEASE-NOTES b/drivers/char/ftape/RELEASE-NOTES deleted file mode 100644 index 03799dbc05a4..000000000000 --- a/drivers/char/ftape/RELEASE-NOTES +++ /dev/null | |||
@@ -1,966 +0,0 @@ | |||
1 | Hey, Emacs, we're -*-Text-*- mode! | ||
2 | |||
3 | ===== Release notes for ftape-3.04d 25/11/97 ===== | ||
4 | - The correct pre-processor statement for "else if" is "#elif" not | ||
5 | "elsif". | ||
6 | - Need to call zft_reset_position() when overwriting cartridges | ||
7 | previously written with ftape-2.x, sftape, or ancient | ||
8 | (pre-ftape-3.x) versions of zftape. | ||
9 | |||
10 | ===== Release notes for ftape-3.04c 16/11/97 ===== | ||
11 | - fdc_probe() was calling DUMPREGS with a result length of "1" which | ||
12 | was just fine. Undo previous change. | ||
13 | |||
14 | ===== Release notes for ftape-3.04b 14/11/97 ===== | ||
15 | |||
16 | - patches/2.x.x/floppy.c.diff was somewhat broken, releasing i/o | ||
17 | regions it never had allocated. | ||
18 | - fdc_probe() was calling DUMPREGS with a result length of "1" instead | ||
19 | of "10" | ||
20 | - Writing deleted data marks if the first segents on track zero are | ||
21 | should work now. | ||
22 | - ftformat should now be able to handle those cases where the tape | ||
23 | drive sets the read only status bit (QIC-40/80 cartridges with | ||
24 | QIC-3010/3020 tape drives) because the header segment is damaged. | ||
25 | - the MTIOCFTCMD ioctl may now be issued by the superuser ONLY. | ||
26 | |||
27 | ===== Release notes for ftape-3.04a 12/11/97 ===== | ||
28 | - Fix an "infinite loop can't be killed by signal" bug in | ||
29 | ftape_get_drive_status(). Only relevant when trying to access | ||
30 | buggy/misconfigured hardware | ||
31 | - Try to compensate a bug in the HP Colorado T3000's firmware: it | ||
32 | doesn't set the write protect bit for QIC80/QIC40 cartridges. | ||
33 | |||
34 | ===== Release notes for ftape-3.04 06/11/97 ===== | ||
35 | - If positioning with fast seeking fails fall back to a slow seek | ||
36 | before giving up. | ||
37 | - (nearly) no retries on "no data errors" when verifying after | ||
38 | formatting. Improved tuning of the bad sector map after formatting. | ||
39 | - the directory layout has changed again to allow for easier kernel | ||
40 | integration | ||
41 | - Module parameter "ftape_tracing" now is called "ft_tracing" because | ||
42 | the "ftape_tracing" variable has the version checksum attached to it. | ||
43 | - `/proc/ftape' interface for 2.0.* kernels. `/proc/ftape' no longer | ||
44 | is a directory but a file that contains all the information formerly | ||
45 | provided in separate files under the `/proc/ftape/' directory. | ||
46 | - Most of the configuration options have been prefixed by "CONFIG_FT_" | ||
47 | in preparation of the kernel inclusion. The Makefiles under | ||
48 | "./ftape/" should be directly usable by the kernel. | ||
49 | - The MODVERSIONS stuff is now auto-detected. | ||
50 | - Broke backslashed multi line options in MCONFIG into separate lines | ||
51 | using GNU-make's "+=" feature. | ||
52 | - The html and dvi version of the manual is now installed under | ||
53 | '/usr/doc/ftape` with 'make install` | ||
54 | - New SMP define in MCONFIG. ftape works with SMP if this is defined. | ||
55 | - attempt to cope with "excessive overrun errors" by gradually | ||
56 | increasing FDC FIFO threshold. But this doesn't seem to have too | ||
57 | much an effect. | ||
58 | - New load time configuration parameter "ft_fdc_rate_limit". If you | ||
59 | encounter too many overrun errors with a 2Mb controller then you | ||
60 | might want to set this to 1000. | ||
61 | - overrun errors on the last sector in a segment sometimes result in | ||
62 | a zero DMA residue. Dunno why, but compensate for it. | ||
63 | - there were still fdc_read() timeout errors. I think I have fixed it | ||
64 | now, please FIXME. | ||
65 | - Sometimes ftape_write() failed to re-start the tape drive when a | ||
66 | segment without a good sector was reached ("wait for empty segment | ||
67 | failed"). This is fixed. Especially important for > QIC-3010. | ||
68 | - sftape (aka ftape-2.x) has vanished. I didn't work on it for | ||
69 | ages. It is probably still possible to use the old code with | ||
70 | ftape-3.04, if one really needs it (BUT RECOMPILE IT) | ||
71 | - zftape no longer alters the contents of already existing volume | ||
72 | table entries, which makes it possible to fill in missing fields, | ||
73 | like time stamps using some user space program. | ||
74 | - ./contrib/vtblc/ contains such a program. | ||
75 | - new perl script ./contrib/scripts/listtape that list the contents of a | ||
76 | floppy tape cartridge parsing the output of "mt volinfo" + "mt fsf" | ||
77 | - the MTWEOF implementation has changed a little bit (after I had a | ||
78 | look at amanda). Calling MTWEOF while the tape is still held open | ||
79 | after writing something to the tape now will terminate the current | ||
80 | volume, and start a new one at the current position. | ||
81 | - the volume table maintained by zftape now is a doubly linked list | ||
82 | that grows dynamically as needed. | ||
83 | |||
84 | formatting floppy tape cartridges | ||
85 | --------------------------------- | ||
86 | * there is a new user space formatting program that does most of the | ||
87 | dirty work in user space (auto-detect, computing the sector | ||
88 | coordinates, adjusting time stamps and statistics). It has a | ||
89 | simple command line interface. | ||
90 | * ftape-format.o has vanished, it has been folded into the low level | ||
91 | ftape.o module, and the ioctl interface into zftape.o. Most of the | ||
92 | complicated stuff has been moved to user space, so there was no | ||
93 | need for a separate module anymore. | ||
94 | * there is a new ioctl MTIOCFTCMD that sends a bare QIC-117 command | ||
95 | to the tape drive. | ||
96 | * there is a new mmap() feature to map the dma buffers into user | ||
97 | space to be used by the user level formatting program. | ||
98 | * Formatting of yet unformatted or totally degaussed cartridges | ||
99 | should be possible now. FIXME. | ||
100 | |||
101 | ===== Release notes for ftape-3.03b, <forgot the exact date> ==== | ||
102 | |||
103 | ftape-3.03b was released as a beta release only. Its main new feature | ||
104 | was support of the DITTO-2GB drive. This was made possible by reverse | ||
105 | engineering done by <fill in his name> after Iomega failed to support | ||
106 | ftape. Although they had promised to do so (this makes me feel a bit | ||
107 | sad and uncomfortable about Iomega). | ||
108 | |||
109 | ===== Release notes for ftape-3.03a, 22/05/97 ==== | ||
110 | |||
111 | - Finally fixed auto-un-loading of modules for kernels > 2.1.18 | ||
112 | - Add an "uninstall" target to the Makefile | ||
113 | - removed the kdtime hack | ||
114 | - texi2www didn't properly set the back-reference from a footnote back | ||
115 | to the regular text. | ||
116 | |||
117 | zftape specific | ||
118 | --------------- | ||
119 | * hide the old compression map volume. Taper doesn't accept the | ||
120 | presence of non-Taper volumes and Taper-written volume on the same | ||
121 | tape. | ||
122 | * EOD (End Of Data) handling was still broken: the expected behavior | ||
123 | is to return a zero byte count at the first attempt to read past | ||
124 | EOD, return a zero byte count at the second attempt to read past | ||
125 | EOD and THEN return -EIO. | ||
126 | |||
127 | ftape-format specific | ||
128 | --------------------- | ||
129 | * Detection of QIC-40 cartridges in select_tape_format() was broken | ||
130 | and made it impossible to format QIC-3010/3020 cartridges. | ||
131 | * There are strange "TR-1 Extra" cartridges out there which weren't | ||
132 | detected properly because the don't strictly conform to the | ||
133 | QIC-80, Rev. N, spec. | ||
134 | |||
135 | ===== Release notes for ftape-3.03, 30/04/97 ===== | ||
136 | |||
137 | - Removed kernel integration code from the package. I plan to provide | ||
138 | a package that can be integrated into the stock kernel separately | ||
139 | (hopefully soon). | ||
140 | As a result, a simple `make' command now will build everything. | ||
141 | - ALL compile time configuration options have been moved to the file | ||
142 | `MCONFIG'. | ||
143 | - Quite a few `low level' changes to allow formatting of cartridges. | ||
144 | - formatting is implemented as a separate module `ftape-format.o'. The | ||
145 | modified `mt' program contains sample code that shows how to use it. | ||
146 | - The VFS interface has been moved from the `ftape.o' module to the | ||
147 | high level modules `zftape.o' resp. `sftape.o'. `ftape.o' contains | ||
148 | the hardware support only. | ||
149 | - A bit of /proc support for kernels > 2.1.28 | ||
150 | - Moved documentation to Doc subdir. INSTALL now contains some real | ||
151 | installation notes. | ||
152 | - `install' target in Makefile. | ||
153 | |||
154 | zftape specific: | ||
155 | ---------------- | ||
156 | |||
157 | - zftape works for large cartridges now ( > 2^31 bytes) | ||
158 | - MTIOCVOLINFO and MTIOCGETSIZE now return the size in KILOBYTES, | ||
159 | NO LONGER in bytes. | ||
160 | |||
161 | - permissions for write access to a cartridge have changed: | ||
162 | * zftape now also takes the file access mode into account | ||
163 | * zftape no longer allows writing in the middle of the recorded | ||
164 | media. The tape has to be positioned at BOT or EOD for write | ||
165 | access. | ||
166 | |||
167 | - MTBSF has changed. It used to position at the beginning of the | ||
168 | previous file when called with count 1. This was different from the | ||
169 | expected behavior for other Un*x tape drivers (i.e. SCSI). MTBSF | ||
170 | with count 1 should merely position at the beginning of the current | ||
171 | volume. Fixed. As a result, `tar --verify' now produces the desired | ||
172 | result: it verifies the last written volume, not the pre-last | ||
173 | written volume. | ||
174 | |||
175 | - The compression map has vanished --> no need for `mt erase' any | ||
176 | more. Fast seeking in a compressed volume is still be possible, but | ||
177 | takes slightly longer. As a side effect, you may experience an | ||
178 | additional volume showing up in front of all others for old | ||
179 | cartridges. This is the tape volume that holds the compression map. | ||
180 | |||
181 | - The compression support for zftape has been moved to a separate | ||
182 | module `zft-compressor'. DON'T forget to load it before trying to | ||
183 | read back compressed volumes. The stock `zftape.o' module probes for | ||
184 | the module `zft-compressor' using the kerneld message channel; you | ||
185 | have to install `zft-compressor.o' in a place where modprobe can | ||
186 | find it if you want to use this. | ||
187 | |||
188 | - New experimental feature that tries to get the broken down GMT time | ||
189 | from user space via a kernel daemon message channel. You need to | ||
190 | compile and start the `kdtime' daemon contained in the contrib | ||
191 | directory to use it. Needed (?) for time stamps in the header | ||
192 | segments and the volume table. | ||
193 | |||
194 | - variable block size mode via MTSETBLK 0 | ||
195 | |||
196 | - keep modules locked in memory after the block size has been changed | ||
197 | |||
198 | sftape specific: | ||
199 | ---------------- | ||
200 | |||
201 | - end of tape handling should be fixed, i.e. multi volume archives | ||
202 | written with `afio' can be read back now. | ||
203 | |||
204 | |||
205 | ===== Release notes for ftape-3.02a, 09/01/97 ===== | ||
206 | |||
207 | No big news: | ||
208 | - call zft_init() resp. sft_init() when compiling the entire stuff | ||
209 | into the kernel image. | ||
210 | - fix bug in ftape-setup.c when NO_TRACE_AT_ALL was defined. | ||
211 | - fix bug in sftape-eof.c/zftape-eof.c for old kernels (1.2.*) | ||
212 | - add support for new module interface for recent kernels | ||
213 | |||
214 | ===== Release notes for ftape-3.02, 16/12/96 ===== | ||
215 | - Fixed the `FDC unlock command failed' bug in fdc-io.c. When the FIFO | ||
216 | was already locked when ftape was loaded, ftape failed to unlock it. | ||
217 | - Fixed compilation of `contrib/gnumt'. It now finds `mtio.h' even if | ||
218 | ftape is NOT included into the kernel source tree. | ||
219 | - fc-10.c: include <asm/io.h> for inb() and outb(). | ||
220 | - ftape/sftape/zftape: all global variable now have either a `ftape_', | ||
221 | a `ft_', `sft_', `zft_' or `qic_' prefix to prevent name clashes | ||
222 | with other parts of the kernel when including ftape into the kernel | ||
223 | source tree. | ||
224 | - Kerneld support has changed. `ftape' now searches for a module | ||
225 | `ftape-frontend' when none of the frontend (`sftape' or `zftape') is | ||
226 | loaded. Please refer to the `Installation/Loading ftape' section of | ||
227 | the TeXinfo manual. | ||
228 | - Add load resp. boot-time configuration of ftape. There are now | ||
229 | variables ft_fdc_base, ft_fdc_dma and ft_fdc_irq corresponding to | ||
230 | the former FDC_BASE etc. compile time definitions. One can also use | ||
231 | the kernel command line parameters to configure the driver if it is | ||
232 | compiled into the kernel. Also, the FC-10/FC-20 support is load-time | ||
233 | configurable now as well as the MACH-II hack (ft_probe_fc10, | ||
234 | resp. ft_mach2). Please refer to the section `Installation/Configure | ||
235 | ftape' of the TeXinfo manual. | ||
236 | - I removed the MODVERSIONS option from `Makefile.module'. Let me alone | ||
237 | with ftape and MODVERSIONS unless you include the ftape sources into | ||
238 | the kernel source tree. | ||
239 | - new vendors in `vendors.h': | ||
240 | * HP Colorado T3000 | ||
241 | * ComByte DoublePlay (including a bug fix for their broken | ||
242 | formatting software, thanks to whraven@njackn.com) | ||
243 | * Iomega DITTO 2GIG. NOTE: this drive cannot work with ftape because | ||
244 | the logical data layout of the cartridges used by this drive does | ||
245 | NOT conform to the QIC standards, it is a special Iomega specific | ||
246 | format. I've sent mail to Iomega but didn't receive an answer | ||
247 | yet. If you want this drive to be supported by ftape, ask Iomega | ||
248 | to give me information about it. | ||
249 | - zftape: | ||
250 | * re-introduced the MTIOC_ZFTAPE_GETBLKSZ ioctl for compatibility | ||
251 | with zftape 1.06a and earlier. Please don't use it when writing | ||
252 | new software, use the MTIOCVOLINFO ioctl instead. | ||
253 | * Major overhaul of the code that updates the header segments. Never | ||
254 | change the tape label unless erasing the tape. Thus we almost | ||
255 | never need to write the header segments, unless we would modify | ||
256 | the bad sector map which isn't done yet. Updating of volume table | ||
257 | and compression map more secure now although it takes a bit | ||
258 | longer. | ||
259 | * Fixed bug when aborting a write operation with a signal: zftape | ||
260 | now finishes the current volume (i.e. writes an eof marker) at the | ||
261 | current position. It didn't before which led to somehow *strange* | ||
262 | behavior in this cases. | ||
263 | * Keep module locked in memory when using it with the non-rewinding | ||
264 | devices and the tape is not logical at BOT. Needed for kerneld | ||
265 | support. | ||
266 | - sftape: | ||
267 | * Keep module locked in memory when using it with the non-rewinding | ||
268 | devices and the tape is not logical at BOT. Needed for kerneld | ||
269 | support. | ||
270 | |||
271 | ===== Release notes for ftape-3.01, 14/11/96 ===== | ||
272 | |||
273 | - Fixed silly bugs in ftape-3.00: | ||
274 | * MAKEDEV.ftape: major device number must be 27, not 23 | ||
275 | * sftape/sftape-read.c: sftape_read_header_segments() called | ||
276 | itself recursively instead of calling ftape_read_header_segment() | ||
277 | * zftape/qic-vtbl.h: conversion of ftape's file marks to zftape's | ||
278 | internal volume table was broken. | ||
279 | * patches/2.x.x/linux-2.0.21.dif: my RCS (resp. CVS) system replaced | ||
280 | the `$Revison:' etc. macros in the `ftape.h' concerning part of the | ||
281 | patch :-( Fixed. | ||
282 | * info/ftape.info: Fixed misspellings (`cp' <-> `cp -r' etc.) | ||
283 | * when ftape/sftape or ftape/zftape was compiled into the kernel the | ||
284 | variable ftape_status was declared twice. Fixed. | ||
285 | * removed reference to undeclared variable kernel_version when not | ||
286 | compiling as module | ||
287 | * fixed a bug introduced by the use of bit-fields for some flags | ||
288 | (i.e. write_protected, no_cartridge, formatted) | ||
289 | * flag `header_read' is now reset correctly to zero when tape is | ||
290 | removed. | ||
291 | - fixed a bug in sftape/sftape-eof.c that was already in the original | ||
292 | ftape code. MTFSF/BSF was not handled correctly when positioned | ||
293 | right before the file mark (think of tar) | ||
294 | - Changed TRACE macros (following a suggestion of Marcin Dalecki) to use | ||
295 | the predefined __FUNCTION__ macro of GCC. Spares about 4k of code. | ||
296 | - added new vendor id for Iomega DITTO 2GIG | ||
297 | - fixed a bug already present in zftape-1.06 when aborting a write | ||
298 | with a signal: we now finish the current volume at that | ||
299 | position. Header segments remain NOT up to date until an explicit call | ||
300 | to MTREW or MTOFFL is done. | ||
301 | |||
302 | ===== Release notes for ftape-3.00, 14/10/96 ===== | ||
303 | |||
304 | - Merged ftape with zftape. There are three modules now: | ||
305 | ftape for the hardware support, sftape for the implementation of the | ||
306 | original ftape eof mark stuff and zftape that implements zftape's way | ||
307 | of handling things (compression, volume table, tape blocks of | ||
308 | constant length) | ||
309 | - Documentation in TeXinfo format in the `info' subdirectory. | ||
310 | - New ioctls for zftape. See zftape/zftape.h | ||
311 | - Dummy formatting ioctl for ftape. See ftape.h | ||
312 | - Kernel patch files for the 2.*.* series to include ftape-3.00 in the | ||
313 | kernel source tree. These includes a kernel compatible Config.in | ||
314 | script and fairly large online information for the kernel configure | ||
315 | script. | ||
316 | - Support for compiling with Linux-1.2.13. | ||
317 | - Modified GNU mt from their cpio package that can handle the new | ||
318 | ioctls. | ||
319 | - ftape/sftape/zftape is kerneld save now! | ||
320 | |||
321 | Notes on sftape: | ||
322 | - sftape implements the eof handling code of the original ftape. If | ||
323 | you like to stick with the original ftape stuff, you have to use | ||
324 | this module, not zftape. | ||
325 | - sftape is kerneld save, unlike the original ftape. | ||
326 | - we keep the entire header segment now in memory, so no need to read | ||
327 | it before updating the header segments. Additional memory | ||
328 | consumption: 256 bytes. | ||
329 | |||
330 | Notes for zftape: | ||
331 | - zftape has support for tapes with format code 6 now, which use a | ||
332 | slightly different volume table format compared with other floppy | ||
333 | tapes. | ||
334 | - new ioctls for zftape. Have a look at zftape/zftape.h | ||
335 | - The internal volume table representation has changed for zftape. Old | ||
336 | cartridges are converted automatically. | ||
337 | - zftape no longer uses compression map segments, which have vanished | ||
338 | from the QIC specs, but creates volume table entry that reserves | ||
339 | enough space for the compression map. | ||
340 | - zftape is kerneld save now. | ||
341 | - we keep the entire header segment now in memory, so no need to read | ||
342 | it before updating the header segments. Additional memory | ||
343 | consumption: 256 bytes. | ||
344 | |||
345 | Notes for contrib/gnumt: | ||
346 | - modified mt from the GNU cpio package that supports all the new | ||
347 | ioctls of zftape. | ||
348 | Notes for contrib/swapout: | ||
349 | - This contains the swapout.c program that was written by Kai | ||
350 | Harrekilde-Pederson. I simply added a Makefile. | ||
351 | |||
352 | ===== Release notes for ftape-2.10, 14/10/96 ===== | ||
353 | |||
354 | The ftape maintainer has changed. | ||
355 | Kai Harrekilde-Petersen <khp@dolphinics.no> | ||
356 | has resigned from maintaining ftape, and I, | ||
357 | Claus-Justus Heine <claus@momo.math.rwth-aachen.de>, | ||
358 | have taken over. | ||
359 | |||
360 | - Added support for tapes with `format code 6', i.e. QIC-3020 tapes | ||
361 | with more than 2^16 segments. | ||
362 | - merged changes made by Bas Laarhoven with ftape-2.09. Refer | ||
363 | to his release notes below. I've included them into this | ||
364 | file unchanged for your reference. | ||
365 | - disabled call stack back trace for now. This new feature | ||
366 | introduced by the interim release 2.0.x still seems to | ||
367 | be buggy. | ||
368 | - Tried to minimize differences between the ftape version | ||
369 | to be included into the kernel source tree and the standalone | ||
370 | module version. | ||
371 | - Reintroduced support for Linux-1.2.13. Please refer to the | ||
372 | Install-guide. | ||
373 | |||
374 | ===== Release notes for ftape-2.09, 16/06/96 ===== | ||
375 | |||
376 | There aren't any really big news in this release, mostly just that I | ||
377 | (the maintainer) have changed my email address (due to a new job). My | ||
378 | new address is <khp@dolphinics.no> | ||
379 | |||
380 | - The CLK_48MHZ and FDC_82078SL options has gone (all 2Mbps cards seem | ||
381 | to use a 48MHz oscillator anyway and I haven't heard of an 'SL | ||
382 | chip out there). | ||
383 | - The S82078B has been `downgraded' to i82077AA compability. | ||
384 | - TESTING option revived. Right now, it'll enable the (seriously broken) | ||
385 | 2Mbps code. If you enable it, you'll experience a tape drive that's | ||
386 | *really* out to lunch! | ||
387 | - Some (bold) changes in the init code. Please notify me if they | ||
388 | break things for you. | ||
389 | |||
390 | ===== Release notes for ftape-2.08, 14/03/96 ===== | ||
391 | |||
392 | If you correct a problem with ftape, please send your patch to | ||
393 | khp@dolphinics.no too. | ||
394 | |||
395 | - Updated to reflect that NR_MEM_LISTS is gone in 1.3.74 | ||
396 | - Teac 700 added to list of known drives. | ||
397 | - The registered device name is now "ft" rather than "ftape". | ||
398 | |||
399 | ===== Release notes for ftape-2.07a, 14/03/96 ===== | ||
400 | |||
401 | Bugfixes by Marcin Dalecki <dalecki@namu03.gwdg.de>: | ||
402 | - In the last release it just compiled against 1.3.70; | ||
403 | now the params to request_irq() and free_irq are() are fixed, so it also | ||
404 | works in 1.3.73 :-) | ||
405 | - Support for modules is now correct for newer kernels. | ||
406 | |||
407 | ===== Release notes for ftape-2.07, 04/03/96 ===== | ||
408 | |||
409 | |||
410 | - ftape updated to compile against 1.3.70. | ||
411 | - Iomega 700 and Wangtek 3200 recognised. | ||
412 | |||
413 | |||
414 | ===== Release notes for ftape-2.06b, 13/02/96 ===== | ||
415 | |||
416 | Another simple bugfix version. | ||
417 | |||
418 | - Jumbo 700 recognised. | ||
419 | - Typo in vendors.h fixed. | ||
420 | |||
421 | |||
422 | ===== Release notes for ftape-2.06a, 10/02/96 ===== | ||
423 | |||
424 | This release is a simple bugfix version. | ||
425 | |||
426 | - Linux/SMP: ftape *should* work. | ||
427 | - FC-10/20: Only accepts IRQs 3-7, or 9. If IRQ 9, properly tell the card | ||
428 | to use IRQ 2. Thanks to Greg Crider (gcrider@iclnet.org) for finding and | ||
429 | locating this bug and testing the patch. | ||
430 | - Insight drive recognised correctly again. | ||
431 | - Motor-on wakeup version of the Iomega 250 drive added | ||
432 | |||
433 | |||
434 | ===== Release notes for ftape-2.06, 28/01/96 ===== | ||
435 | |||
436 | Special thanks go to Neal Friedman and Steven Sorbom for their | ||
437 | help in producing and testing this release. | ||
438 | |||
439 | I have continued to clean up the code, with an eye towards inclusion | ||
440 | of ftape in Linus' official kernel (In fact, as I type this, I am | ||
441 | running on a kernel with ftape support statically linked). I have | ||
442 | test-compiled ftape against my 1.2.13 tree without problems. | ||
443 | Hopefully, everything should be OK for the v1.2.x people. | ||
444 | |||
445 | WARNING! Alan Cox has mailed me that ftape does *NOT* work with | ||
446 | Linux/SMP. If you try to run ftape under Linux/SMP, it will cause a | ||
447 | kernel deadlock (which is worse than a panic). | ||
448 | |||
449 | - QIC-3020/TR-3: 1Mbps support works. Neal is capable of reading and | ||
450 | writing data to a tape. ftape will automatically detect the type of | ||
451 | tape (e.g. TR-3 vs QIC-80) and move the fdc in and out of | ||
452 | "perpendicular mode" as necessary. | ||
453 | - 2Mbps support is disabled by default, since it is not fully | ||
454 | debugged. If you are adventurous, remove -DFDC_82078SL in the | ||
455 | Makefile and see what happens :-) | ||
456 | - fdc detection: silly bugs removed (Only 2Mbps fdcs were affected) | ||
457 | and added detection of the National Semiconductors PC8744 fdc chip | ||
458 | (used in the PC873xx "super-IO" chips). | ||
459 | - Removed warning about incompatible types when compiling with Linux | ||
460 | 1.2.x. | ||
461 | - README.PCI updated with info about the DELL Dimension XPS P90. | ||
462 | - Connor TST3200R added to detected drives. | ||
463 | - `swapout' utility added to distribution. It will dirty 5Meg of | ||
464 | memory, trying to swap out other programs. Just say `make swapout' | ||
465 | to build it. ftape will do this automatically Real Soon Now (ie: | ||
466 | when I have found out which kernel memory alloc function to call). | ||
467 | |||
468 | |||
469 | ===== Release notes for ftape-2.05, 08/01/96 ===== | ||
470 | |||
471 | - For v1.2.x Kernels, you must apply the patch linux-1.2/ksyms.patch to | ||
472 | the kernel and rebuild it (it adds the __get_dma_pages symbol to | ||
473 | ksyms.c). | ||
474 | - Included new asm-i386/io.h file from v1.3.x kernel series, to enable | ||
475 | gcc v.2.7.[12] to compile v1.2.x kernels (linux-1.2/io.h). | ||
476 | - Module versions: If you wish to compile ftape as a versioned module, | ||
477 | you must first compile your kernel with CONFIG_MODVERSIONS=y. | ||
478 | Otherwise, you will get complaints that <linux/modversions.h> does not | ||
479 | exist (if that happens, a `touch modversions.h' will help you out). | ||
480 | - CLK_48MHZ: new define in the Makefile (default: non-zero). If you have | ||
481 | a tape controller card that uses the i82078(-1) chip, but cannot get | ||
482 | it to work with ftape, try set it to 0 (and please report this). | ||
483 | - QIC-3010/3020: Complete support is still missing, but will hopefully | ||
484 | come soon. Steven Sorbom has kindly provided me with hints about | ||
485 | this. Writing of QIC-3020 tapes definitely does NOT work (do not try | ||
486 | it! - the drive will not be in "perpendicular mode" and this will ruin | ||
487 | the formatting info on the tape). | ||
488 | - ftape_num_buffers is out of fashion: use NR_BUFFERS instead (and | ||
489 | recompile if you want to change it :-). | ||
490 | |||
491 | |||
492 | ===== Release notes for ftape-2.04, 01/01/96 ===== | ||
493 | |||
494 | This version by Kai Harrekilde-Petersen <khp@dolphinics.no> | ||
495 | |||
496 | - ALERT! Support for Kernels earlier then v1.1.85 is about to go away. | ||
497 | I intend to clean up some of the code (getting rid of an annoyingly | ||
498 | large numbers of #ifdef mostly), which means that support for | ||
499 | pre-1.1.85 kernels must go as well. | ||
500 | - NR_FTAPE_BUFFERS is gone; You can instead select the number of dma | ||
501 | buffers by saying `insmod ftape.o ftape_num_buffer=<n>' instead. | ||
502 | - Configure script gone. ftape will now automagically determine your | ||
503 | kernel version by /usr/include/linux/version.h instead. | ||
504 | - CONFIG_MODVERSIONS now work. All combinations of versioned / | ||
505 | unversioned kernel and ftape module works (at least with my 1.3.52 | ||
506 | kernel). | ||
507 | - If you have problems with inserting ftape into an old (1.2.x) | ||
508 | kernel (e.g. insmod says "1.2.8 does not match 1.2.8), recompile | ||
509 | your modules utilities with your new compiler. | ||
510 | - Reveal TB1400 drive added to vendors.h | ||
511 | - Support for the i82078-1 (2Mbps) chip is coming along. The | ||
512 | biggest problem is that I don't have such a card, which makes | ||
513 | testing / debugging somewhat problematic. The second biggest | ||
514 | problem is that I do not have the QIC-3010/3020 standards either. | ||
515 | Status right now is that the chip is detected, and it should be | ||
516 | possible to put it into 2Mbps mode. However, I do not know what | ||
517 | "extras" are needed to complete the support. Although putting the | ||
518 | i82078 into 1Mbps mode ought to work out of the box, it doesn't | ||
519 | (right now, ftape complains about id am errors). | ||
520 | |||
521 | |||
522 | ===== Release notes for ftape-2.04beta5, 29/12/95 ===== | ||
523 | |||
524 | Bas offline linux-tape | ||
525 | ---------------------- | ||
526 | For reasons only known to the majordomo mail list processor, Bas was | ||
527 | kicked off the linux-tape list sometime during the summer. Being | ||
528 | overworked at his for-pay job, he didn't notice it much. Instead I | ||
529 | (Kai, khp@dolphinics.no) has worked on ftape to produce the 2.04(beta) | ||
530 | version. | ||
531 | |||
532 | zftape | ||
533 | ------ | ||
534 | Note that there exists a much improved version of ftape, written by | ||
535 | Claus-Justus Heine <claus@willi.math.rwth-aachen.de> which is named | ||
536 | zftape, which conforms to the QIC-80 specs on how to mark backups, and | ||
537 | is capable of doing automatic compression. However, zftape makes | ||
538 | substantial changes to ftape, and I (Kai) have therefore declined to | ||
539 | integrate zftape into ftape. Hopefully, this will happen soon. | ||
540 | |||
541 | CONFIG_QIC117 removed from the kernel | ||
542 | ------------------------------------- | ||
543 | The biggest change of all is that ftape now will allocate its dma | ||
544 | buffers when it is inserted. The means that the CONFIG_QIC117 option | ||
545 | has disappeared from the Linux kernel as of v1.3.34. If you have an | ||
546 | earlier kernel, simply answer 'no' to the question will do the trick | ||
547 | (if you get complains about __get_free_pages() missing, contact the | ||
548 | linux-tape mailing list). | ||
549 | |||
550 | Note that ftape-2.04beta will work equally well on kernels with and | ||
551 | without `ftape support'. The only catch is, that you will waste | ||
552 | around 96-128Kb of precious DMA'able memory on a box that has ftape | ||
553 | support compiled in. | ||
554 | |||
555 | Now for the real changes: | ||
556 | |||
557 | - FC-20 can now use DMA channels 1, 2, and 3. Thanks to Daniel | ||
558 | Cohen, catman@wpi.edu. | ||
559 | - ftape no longer requires a (gigantic) 96Kb buffer to be statically | ||
560 | allocated by the kernel. | ||
561 | - Added new Iomega drive (8882) to vendors.h | ||
562 | - -fno-strength-reduce added to Makefile, since GCC is broken. | ||
563 | - i82078-1 (2Mbps) FDC support started. | ||
564 | |||
565 | |||
566 | ===== Release notes for ftape-2.03b, 27/05/95 ===== | ||
567 | |||
568 | - Prevented verify_area to return error if called with zero length. | ||
569 | - Fixed a bug in flush_buffers that caused too much padding to be | ||
570 | written when a final segment had bad sectors. | ||
571 | - Increased maximum fast-seek overshoot value from 5 to 10 segments. | ||
572 | - Breaking loop after 5 retries when positioning fails. | ||
573 | - Fixed wrong calculation of tape length for QIC-3010 and QIC-3020 | ||
574 | tapes (densities were swapped). | ||
575 | - Fixed wrong calculation of overshoot on seek_forward: Wrong sign | ||
576 | of error. | ||
577 | - Suppress (false) error message due to new tape loaded. | ||
578 | - Added two new CMS drives (11c3 and 11c5) to vendors.h. | ||
579 | |||
580 | |||
581 | ===== Release notes for ftape-2.03a, 09/05/95 ===== | ||
582 | |||
583 | - Fixed display of old error (even if already cleared) in ftape_open. | ||
584 | - Improved tape length detection, ioctls would fail for 425 ft tapes. | ||
585 | Until the tape length is calculated with data from the header | ||
586 | segment, we'll use worst-case values. | ||
587 | - Clear eof_mark after rewinding ioctls. | ||
588 | - Fixed wrong version message (2.03 had 2.02g id). | ||
589 | - Fixed bug that caused the fdc to be reset very frequently. | ||
590 | This shouldn't affect normal operation but the timing of the | ||
591 | report routines has changed again and that may cause problems. | ||
592 | We'll just have to find out.... | ||
593 | - Implemented correct write precompensation setting for QIC-3010/3020. | ||
594 | - Cleaned up fdc_interrupt_wait routine. Hope it still works :-) | ||
595 | - Finally removed (already disabled) special eof mark handling for | ||
596 | gnu tar. | ||
597 | - Changed order of get_dma_residue and disable_dma in fdc-isr.c | ||
598 | because the current order would fail on at least one system. | ||
599 | We're back to the original order again, hope (and expect) this | ||
600 | doesn't break any other system. | ||
601 | |||
602 | |||
603 | ===== Release notes for ftape-2.03, 07/05/95 ===== | ||
604 | |||
605 | (Changes refer to the first ftape-2.02 release) | ||
606 | |||
607 | Support for wide and extended length tapes | ||
608 | ------------------------------------------ | ||
609 | The Conner TSM 420 and 850 drives are reported to be working. | ||
610 | I haven't received any reports about other brands; the TSM 420 | ||
611 | and 850 seem to be the most widely used wide drives. | ||
612 | Extended length tapes (425 ft) with normal QIC-80 drives | ||
613 | are operating too (At least I've had no reports stating otherwise). | ||
614 | _Not_ yet completely supported (although they may work) are | ||
615 | QIC-3020 drives and 2 Mbps floppy disk controllers won't work at | ||
616 | the highest speed. | ||
617 | If someone is kind enough to send me one of these, I'll include | ||
618 | support for it too ;-) | ||
619 | |||
620 | Easier configuration | ||
621 | -------------------- | ||
622 | Problems due to wrong settings in the Makefile are prevented | ||
623 | by using a configuration script that sets the necessary (kernel | ||
624 | version dependent) compile time options. | ||
625 | This kernel version is now determined from the sources found | ||
626 | at /usr/src/linux, or if not found, the old way using | ||
627 | /proc/version. | ||
628 | Versioned modules will be used automatically when supported | ||
629 | by- and configured in- the kernel. | ||
630 | Note that the current modules code (1.1.87) is still broken | ||
631 | and _needs_ the fix included in the insmod directory. | ||
632 | Please don't send me any more Oops reports caused by insmod :-( | ||
633 | |||
634 | Reduced module size | ||
635 | ------------------- | ||
636 | The standard module size is much reduced and some compile time | ||
637 | options can even reduce it further. (I don't recommend this | ||
638 | for normal use but it can be handy for rescue diskettes) | ||
639 | |||
640 | Option: Approx. module size: | ||
641 | |||
642 | <standard> 150 Kb | ||
643 | NO_TRACE 125 Kb | ||
644 | NO_TRACE_AT_ALL 67 Kb | ||
645 | |||
646 | |||
647 | Much improved driver interruption | ||
648 | --------------------------------- | ||
649 | Most possible loops have been broken and signal detection | ||
650 | has been improved. | ||
651 | In most cases the driver can be aborted by ^C (SIGINT) and | ||
652 | SIGKILL (kill -9) will generate be a sure kill. | ||
653 | (Note that aborting a tape operation may damage the last | ||
654 | data written to tape) | ||
655 | |||
656 | Improved error recovery | ||
657 | ----------------------- | ||
658 | Ftape now returns an error (ENODATA) to the application if | ||
659 | a segment proves to be unrecoverable and then skips the | ||
660 | bad segment. | ||
661 | This causes most applications to continue to work (tar | ||
662 | and afio) loosing only a small amount (up to 29 Kb) of data. | ||
663 | Retried read operations will now be done slightly off-track | ||
664 | to improve the chance of success. Serious head off-track | ||
665 | errors will be detected. | ||
666 | |||
667 | FC-10 and FC-20 controllers | ||
668 | --------------------------- | ||
669 | Ftape now supports both the old CMS FC-10 and the newer FC-20 | ||
670 | controllers. | ||
671 | Because the operation of these cards is still undocumented, | ||
672 | thus far they will only work with the default settings (See | ||
673 | Makefile). Any feed-back on how to use them with other settings | ||
674 | will be welcome ! | ||
675 | Compilation will fail if one changes the settings to illegal | ||
676 | values. | ||
677 | |||
678 | Kernels and compilers | ||
679 | --------------------- | ||
680 | Ftape is currently being developed using the 2.5.8 compiler. | ||
681 | The older 2.4.5 probably works too (Set option in Makefile!). | ||
682 | I have no experience with any later compilers nor Elf support. | ||
683 | Any information on this is welcome. | ||
684 | The latest kernel I have tested ftape with is 1.2.6. | ||
685 | |||
686 | Compression | ||
687 | ----------- | ||
688 | An impressive collection of changes for ftape including | ||
689 | on-the-fly compression is still lying on my desk. | ||
690 | If 2.03 proves to be reliable I might start integrating these | ||
691 | but as usual, I'm short in time :-( | ||
692 | |||
693 | Formatting | ||
694 | ---------- | ||
695 | There is still no way to format tapes under Linux. As far as | ||
696 | I know all attempts to write such a program have died now. | ||
697 | Since formatted tapes are rather common now, I think all we | ||
698 | need is a utility that writes a worst case pattern and verifies | ||
699 | that with the drive put in verify mode, reducing margins. | ||
700 | Any takers ? | ||
701 | |||
702 | Furthermore | ||
703 | ----------- | ||
704 | Cleaned up messages. | ||
705 | Prepared to support multiple tape drives on one fdc. | ||
706 | Thanks to all the people who sent bug reports and helped me | ||
707 | improve the driver. Without trying to be complete I'll mention | ||
708 | Gary Anderson (without his accurate reports and unreliable | ||
709 | hardware there wouldn't be a 2.03), Stefan Kneifel (FC-20), | ||
710 | Robert Broughton (FC-20, you were almost there ;-), Bjorn | ||
711 | Ekwall (for the versioned modules and buggy insmod ;-), Peter | ||
712 | Fox, Christopher Oliver, Ralph Whittaker and not the least | ||
713 | Linus Torvalds (for Linux and keeping me busy because of | ||
714 | changes to the kernel ;-) | ||
715 | Thanks to anyone I forgot, for the bug reports, the ftape | ||
716 | bashing and the mental support... | ||
717 | |||
718 | |||
719 | That's it for now. Have Fun, | ||
720 | |||
721 | Bas. | ||
722 | |||
723 | |||
724 | ===== Release notes for ftape-2.02g, 06/05/95 ===== | ||
725 | |||
726 | - Added extra test to break read-id loop with signal. | ||
727 | - Changed rewind code to handle negative overshoot for drives | ||
728 | that take very long to start or stop. | ||
729 | - Let use of get/set i/o-regions depend on kernel version. | ||
730 | - Changed code to use a more general test for conditional | ||
731 | compilations depending on kernel version. | ||
732 | - Improved micro-step functionality to go off-track only | ||
733 | while reading (id & data). | ||
734 | - Added failure on tape-not-referenced bit in ftape_command. | ||
735 | - Added FOREVER option to read-wait routine. | ||
736 | - Changed read-id to use shorter timeout causing smaller | ||
737 | rewinds on timeout. | ||
738 | - Made kernel-interface functions static. | ||
739 | |||
740 | |||
741 | ===== Release notes for ftape-2.02f, 03/05/95 ===== | ||
742 | |||
743 | - Added support for dual tape drives on my system, extended Configure | ||
744 | script to detect host 'dodo'. | ||
745 | - Log media defect in history if ecc failed and no data was returned. | ||
746 | - Fixed Configure script that was failing for kernel versions with | ||
747 | double digit version or revision numbers. | ||
748 | |||
749 | |||
750 | ===== Release notes for ftape-2.02e, 01/05/95 ===== | ||
751 | |||
752 | - Fixed reposition loop at logical eot (failing read_id). | ||
753 | - Fixed 34 segment offset when rewinding. | ||
754 | - Added fast seek capability for more than 255 segments. | ||
755 | - Fixed wrong busy result from ftape_command causing reverse | ||
756 | seek to fail. | ||
757 | - Added breakout from infinite rewind loop (if something fails). | ||
758 | |||
759 | |||
760 | ===== Release notes for ftape-2.02d, 30/04/95 ===== | ||
761 | |||
762 | - Improved abortion on signals: Interrupt will make a graceful | ||
763 | exit, Kill will be less nice and should be used if everything | ||
764 | else fails. | ||
765 | - Included check for tape-head off track. | ||
766 | - Implemented exit from tape-start loop. | ||
767 | - Added kernel io-port registration. | ||
768 | - Implemented skip of failing segment (ENODATA) on ecc failure. | ||
769 | This allows afio and tar to continue when the tape is damaged. | ||
770 | - Made distinction between drive names with different codes. | ||
771 | |||
772 | |||
773 | ===== Release notes for ftape-2.02c, 22/04/95 ===== | ||
774 | |||
775 | - Fixed too tight command queueing after tape stop/pause command | ||
776 | issued from within interrupt service routine (Showed as timeout | ||
777 | on Acknowledge errors during retries on some systems) | ||
778 | - Tried to fix timeouts when using 425 ft tape because the extended | ||
779 | length doesn't seem to be detected by the hardware. | ||
780 | We now use the format code from the header segment so adjust the | ||
781 | timing after reading the header segment. | ||
782 | - Fixed some messages stating 'unexpected something...' being not | ||
783 | unexpected anymore. | ||
784 | - Started preparations for merge of dynamic buffer allocation and | ||
785 | compression code. | ||
786 | - Changed some debug messages to include relevant segment information | ||
787 | at level 4. | ||
788 | - Included early bail-out when drive offline, preventing a lot of | ||
789 | false messages. | ||
790 | - Moved ftape_parameter_xxx() offsets into function instead of in calls. | ||
791 | - Removed 'weird, drive busy but no data' error when caused by | ||
792 | an error during a read-id. | ||
793 | - Improved 'timeout on acknowledge' diagnostics. | ||
794 | - Moved MODULE option into Configure. | ||
795 | - Reduced code size when no tracing at all was set (Claus Heine). | ||
796 | - No longer log error code 0 (no error) as an error. | ||
797 | |||
798 | |||
799 | ===== Release notes for ftape-2.02b, 09/04/95 ===== | ||
800 | |||
801 | - Relaxed timing for status operation and displaying | ||
802 | abnormal results. Hopefully this shows what's going | ||
803 | wrong with the Conner TSM850R drives. | ||
804 | - Created script for configuration, using version number | ||
805 | of kernel source if available, otherwise /proc/version. | ||
806 | - Fixed conditionals in kernel-interface.c. | ||
807 | - Removed unavoidable TRACE output. | ||
808 | |||
809 | |||
810 | ===== Release notes for ftape-2.02a, 01/04/95 ===== | ||
811 | |||
812 | - Implemented `new-style' (versioned) modules support for new | ||
813 | kernels. | ||
814 | - Reduced size of module by moving static data to bss. | ||
815 | - Now using version number of kernel source instead of running | ||
816 | kernel for kernel versions >= 1.1.82 | ||
817 | - Added feedback on drive speeds to vendor information. | ||
818 | - Included fixed insmod sources to distribution (Let's hope | ||
819 | the modules distribution get fixed soon :-/). | ||
820 | |||
821 | Note that I haven't yet implemented any of the code extension I | ||
822 | received. I hope to find some time to do this soon. | ||
823 | |||
824 | |||
825 | ===== Release notes for ftape-2.02, 15/01/95 ===== | ||
826 | |||
827 | |||
828 | - Fixed failing repositioning when overshoot was incremented. | ||
829 | - Fixed rate selection: Because of a deficiency in the QIC-117 | ||
830 | specification one cannot distinguish between a not implemented | ||
831 | and a failing command. Therefor we now try to find out if the | ||
832 | drive does support this command before usage. | ||
833 | - Fixed error retry using wrong offset in fdc-isr. | ||
834 | - Improved retry code to retry only once on a single no-data | ||
835 | error in a segment. | ||
836 | - Validate sector number extracted from eof mark because an | ||
837 | invalid file mark (due to ???) could cause kernel panic. | ||
838 | - Split ftape-io.c into ftape-io.c and ftape-ctl.c files. | ||
839 | - Corrected too high media error count after writing to | ||
840 | a bad tape. | ||
841 | - Added #include <asm/segment.h> again because old kernel versions | ||
842 | need it. | ||
843 | - Fixed fdc not being disabled when open failed because no tape | ||
844 | drive was found. | ||
845 | - Fixed problem with soft error in sector 32 (shift operator with | ||
846 | shiftcount 32 is not defined). | ||
847 | |||
848 | |||
849 | ===== Release notes for ftape-2.01, 08/01/95 ===== | ||
850 | |||
851 | |||
852 | - Removed TESTING setting from distributed Makefile. | ||
853 | - Fixed `mt asf' failure: Rewind was deferred to close which | ||
854 | overruled the fsf ioctl. | ||
855 | - Prevented non-interruptible commands being interrupted. | ||
856 | - Added missing timeout.pause setting. | ||
857 | - Maximum tape speed read from drive type information table. | ||
858 | If the information is not in the table (0) the drive will | ||
859 | determine the speed itself and put a message in the logfile. | ||
860 | This information should then be added to the table in the | ||
861 | vendors.h file (and reported to me). | ||
862 | - Added call to ftape_init_drive after soft reset for those | ||
863 | (antique) drives that don't do an implicit seek_load_point | ||
864 | after a reset or power up. | ||
865 | - Don't try to set data rate if reset failed. | ||
866 | - Prevent update of seek variables when starting from the | ||
867 | beginning or the end of the tape. | ||
868 | - Fixed wrong adjustment of overshoot in seek_forward(). | ||
869 | - Added sync to Makefile (again). | ||
870 | - Added code to diagnose timer problems (calibr.c). | ||
871 | - Replaced time differences by timediff calls. | ||
872 | - Removed reference to do_floppy from object for recent kernels. | ||
873 | - Fixed wrong display of 'failing dma controller' message. | ||
874 | - Removed various no longer used #include statements. | ||
875 | - Added max. tape speed value to vendor-struct. | ||
876 | - Changed ftape-command to check pre-conditions and wait | ||
877 | if needed. | ||
878 | - Further updated qic117.h to rev G. | ||
879 | - Combined command name table and restrictions table to one. | ||
880 | Extended this table with some new fields. | ||
881 | - Increased timeout on Ack timer value and included code to | ||
882 | report out of spec behaviour. | ||
883 | - Increased rewind timeout margin to calculated + 20%. | ||
884 | - Improved data rate selection so it won't fail on some | ||
885 | older (pre standard) drives. | ||
886 | - Changed initialisation code so drive will be rewound if the | ||
887 | driver is reloaded and the tape is not at bot. | ||
888 | - Moved some of the flush operations from close to the ioctls. | ||
889 | - Added exit code value to failing verify area message. | ||
890 | - Loop until tape halted in smart-stop. | ||
891 | - Fast seek handled specially if located at bot or eot. | ||
892 | - Being more conservative on overshoot value. | ||
893 | |||
894 | |||
895 | ===== Release notes for ftape-2.00, 31/12/94 ===== | ||
896 | |||
897 | The Install-guide is completely rewritten and now also includes | ||
898 | some information on how to use the driver. If you're either new | ||
899 | to ftape or new to Unix tape devices make sure to read it ! | ||
900 | |||
901 | If you own a pci system and experience problems with the | ||
902 | ftape driver make sure to read the README.PCI file. It contains | ||
903 | some hints on how to fix your hardware. | ||
904 | |||
905 | For anybody who hasn't noticed: The version number of the | ||
906 | driver has been incremented (The latest released version has | ||
907 | been version 1.14d). | ||
908 | This has been done for two major reasons: | ||
909 | |||
910 | o A new (better) error recovery scheme is implemented. | ||
911 | o Support for new drive types has been added. | ||
912 | |||
913 | All these improvements/changes will probably include a couple | ||
914 | of new (and old?) bugs. If you encounter any problems that you think | ||
915 | I'm not yet aware of, feel free to send a report to <bas@vimec.nl>. | ||
916 | I recommend keeping a version of ftape-1.14d available, just | ||
917 | in case ;-) | ||
918 | |||
919 | This version should work with all kernel versions from 1.0.9 up | ||
920 | to 1.1.72 (and probably earlier and later versions too). | ||
921 | |||
922 | |||
923 | Major new features: | ||
924 | |||
925 | - Better handling of tapes with defects: When a sector repeatedly | ||
926 | (SOFT_RETRIES in ftape.h) cannot be written to or read from it is | ||
927 | marked as an hard error and gets skipped. | ||
928 | The error correction code can handle up to three of these hard | ||
929 | errors provided there are no other errors in that segment (32 Kb). | ||
930 | |||
931 | - Allows writing to tapes with defects (although the risk of loosing | ||
932 | data increases !) | ||
933 | Look for the media-defects entry printed with the statistics when | ||
934 | the tape is closed. A non-zero value here shows a bad tape. | ||
935 | [the actual count is wrong (too high), this is a known bug]. | ||
936 | |||
937 | - Use of backup header segment if first one is failing. | ||
938 | |||
939 | - Support for extended length tapes with QIC-80: both 425 and 1100 ft. | ||
940 | 0.25 inch tapes are now recognized and handled. | ||
941 | |||
942 | - Support for new QIC-80 drives with 8 mm `wide' tapes (e.g. Conner | ||
943 | TSM 420). | ||
944 | |||
945 | - Support for new QIC-3010 and QIC-3020 drives (experimental) with | ||
946 | both 0.25 inch and 8 mm tapes. | ||
947 | |||
948 | Some minor features were added, a couple of small bugs were fixed and | ||
949 | probably some new ones introduced ;-). | ||
950 | |||
951 | [lseek() didn't make it into this version] | ||
952 | |||
953 | Have fun, | ||
954 | |||
955 | Bas. | ||
956 | ---- | ||
957 | LocalWords: ftape MCONFIG mt VFS zftape resp sftape proc subdir MTIOCVOLINFO | ||
958 | LocalWords: MTIOCGETSIZE BOT EOD MTBSF zft kerneld modprobe kdtime contrib TR | ||
959 | LocalWords: MTSETBLK afio uninstall texi www EIO QIC init sft eof aka dma GB | ||
960 | LocalWords: SIGKILL MTIOCFTCMD mmap Iomega FDC fdc io gnumt mtio fc asm inb | ||
961 | LocalWords: outb ft qic frontend TeXinfo irq mach MODVERSIONS CONFIG html dvi | ||
962 | LocalWords: usr doc SMP Mb Dunno FIXME vtblc perl listtape volinfo fsf MTWEOF | ||
963 | LocalWords: amanda degaussed ComByte DoublePlay whraven njackn com MTIOC vtbl | ||
964 | LocalWords: GETBLKSZ MAKEDEV zftape's linux dif CVS Revison cp MTREW MTOFFL | ||
965 | LocalWords: MTFSF BSF Marcin Dalecki GCC Config cpio swapout Kai Harrekilde | ||
966 | LocalWords: Pederson khp dolphinics Justus claus momo rwth aachen Laarhoven | ||
diff --git a/drivers/char/ftape/compressor/Makefile b/drivers/char/ftape/compressor/Makefile deleted file mode 100644 index 1fbd6c4019db..000000000000 --- a/drivers/char/ftape/compressor/Makefile +++ /dev/null | |||
@@ -1,31 +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 | # $Source: /homes/cvs/ftape-stacked/ftape/compressor/Makefile,v $ | ||
19 | # $Revision: 1.1 $ | ||
20 | # $Date: 1997/10/05 19:12:28 $ | ||
21 | # | ||
22 | # Makefile for the optional compressor for th zftape VFS | ||
23 | # interface to the QIC-40/80/3010/3020 floppy-tape driver for | ||
24 | # Linux. | ||
25 | # | ||
26 | |||
27 | obj-$(CONFIG_ZFT_COMPRESSOR) += zft-compressor.o | ||
28 | |||
29 | zft-compressor-objs := zftape-compress.o lzrw3.o | ||
30 | |||
31 | CFLAGS_lzrw3.o := -O6 -funroll-all-loops | ||
diff --git a/drivers/char/ftape/compressor/lzrw3.c b/drivers/char/ftape/compressor/lzrw3.c deleted file mode 100644 index a032a0ee2a99..000000000000 --- a/drivers/char/ftape/compressor/lzrw3.c +++ /dev/null | |||
@@ -1,743 +0,0 @@ | |||
1 | /* | ||
2 | * $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.c,v $ | ||
3 | * $Revision: 1.1 $ | ||
4 | * $Date: 1997/10/05 19:12:29 $ | ||
5 | * | ||
6 | * Implementation of Ross Williams lzrw3 algorithm. Adaption for zftape. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include "../compressor/lzrw3.h" /* Defines single exported function "compress". */ | ||
11 | |||
12 | /******************************************************************************/ | ||
13 | /* */ | ||
14 | /* LZRW3.C */ | ||
15 | /* */ | ||
16 | /******************************************************************************/ | ||
17 | /* */ | ||
18 | /* Author : Ross Williams. */ | ||
19 | /* Date : 30-Jun-1991. */ | ||
20 | /* Release : 1. */ | ||
21 | /* */ | ||
22 | /******************************************************************************/ | ||
23 | /* */ | ||
24 | /* This file contains an implementation of the LZRW3 data compression */ | ||
25 | /* algorithm in C. */ | ||
26 | /* */ | ||
27 | /* The algorithm is a general purpose compression algorithm that runs fast */ | ||
28 | /* and gives reasonable compression. The algorithm is a member of the Lempel */ | ||
29 | /* Ziv family of algorithms and bases its compression on the presence in the */ | ||
30 | /* data of repeated substrings. */ | ||
31 | /* */ | ||
32 | /* This algorithm is unpatented and the code is public domain. As the */ | ||
33 | /* algorithm is based on the LZ77 class of algorithms, it is unlikely to be */ | ||
34 | /* the subject of a patent challenge. */ | ||
35 | /* */ | ||
36 | /* Unlike the LZRW1 and LZRW1-A algorithms, the LZRW3 algorithm is */ | ||
37 | /* deterministic and is guaranteed to yield the same compressed */ | ||
38 | /* representation for a given file each time it is run. */ | ||
39 | /* */ | ||
40 | /* The LZRW3 algorithm was originally designed and implemented */ | ||
41 | /* by Ross Williams on 31-Dec-1990. */ | ||
42 | /* */ | ||
43 | /* Here are the results of applying this code, compiled under THINK C 4.0 */ | ||
44 | /* and running on a Mac-SE (8MHz 68000), to the standard calgary corpus. */ | ||
45 | /* */ | ||
46 | /* +----------------------------------------------------------------+ */ | ||
47 | /* | DATA COMPRESSION TEST | */ | ||
48 | /* | ===================== | */ | ||
49 | /* | Time of run : Sun 30-Jun-1991 09:31PM | */ | ||
50 | /* | Timing accuracy : One part in 100 | */ | ||
51 | /* | Context length : 262144 bytes (= 256.0000K) | */ | ||
52 | /* | Test suite : Calgary Corpus Suite | */ | ||
53 | /* | Files in suite : 14 | */ | ||
54 | /* | Algorithm : LZRW3 | */ | ||
55 | /* | Note: All averages are calculated from the un-rounded values. | */ | ||
56 | /* +----------------------------------------------------------------+ */ | ||
57 | /* | File Name Length CxB ComLen %Remn Bits Com K/s Dec K/s | */ | ||
58 | /* | ---------- ------ --- ------ ----- ---- ------- ------- | */ | ||
59 | /* | rpus:Bib.D 111261 1 55033 49.5 3.96 19.46 32.27 | */ | ||
60 | /* | us:Book1.D 768771 3 467962 60.9 4.87 17.03 31.07 | */ | ||
61 | /* | us:Book2.D 610856 3 317102 51.9 4.15 19.39 34.15 | */ | ||
62 | /* | rpus:Geo.D 102400 1 82424 80.5 6.44 11.65 18.18 | */ | ||
63 | /* | pus:News.D 377109 2 205670 54.5 4.36 17.14 27.47 | */ | ||
64 | /* | pus:Obj1.D 21504 1 13027 60.6 4.85 13.40 18.95 | */ | ||
65 | /* | pus:Obj2.D 246814 1 116286 47.1 3.77 19.31 30.10 | */ | ||
66 | /* | s:Paper1.D 53161 1 27522 51.8 4.14 18.60 31.15 | */ | ||
67 | /* | s:Paper2.D 82199 1 45160 54.9 4.40 18.45 32.84 | */ | ||
68 | /* | rpus:Pic.D 513216 2 122388 23.8 1.91 35.29 51.05 | */ | ||
69 | /* | us:Progc.D 39611 1 19669 49.7 3.97 18.87 30.64 | */ | ||
70 | /* | us:Progl.D 71646 1 28247 39.4 3.15 24.34 40.66 | */ | ||
71 | /* | us:Progp.D 49379 1 19377 39.2 3.14 23.91 39.23 | */ | ||
72 | /* | us:Trans.D 93695 1 33481 35.7 2.86 25.48 40.37 | */ | ||
73 | /* +----------------------------------------------------------------+ */ | ||
74 | /* | Average 224401 1 110953 50.0 4.00 20.17 32.72 | */ | ||
75 | /* +----------------------------------------------------------------+ */ | ||
76 | /* */ | ||
77 | /******************************************************************************/ | ||
78 | |||
79 | /******************************************************************************/ | ||
80 | |||
81 | /* The following structure is returned by the "compress" function below when */ | ||
82 | /* the user asks the function to return identifying information. */ | ||
83 | /* The most important field in the record is the working memory field which */ | ||
84 | /* tells the calling program how much working memory should be passed to */ | ||
85 | /* "compress" when it is called to perform a compression or decompression. */ | ||
86 | /* LZRW3 uses the same amount of memory during compression and decompression. */ | ||
87 | /* For more information on this structure see "compress.h". */ | ||
88 | |||
89 | #define U(X) ((ULONG) X) | ||
90 | #define SIZE_P_BYTE (U(sizeof(UBYTE *))) | ||
91 | #define SIZE_WORD (U(sizeof(UWORD ))) | ||
92 | #define ALIGNMENT_FUDGE (U(16)) | ||
93 | #define MEM_REQ ( U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE ) | ||
94 | |||
95 | static struct compress_identity identity = | ||
96 | { | ||
97 | U(0x032DDEA8), /* Algorithm identification number. */ | ||
98 | MEM_REQ, /* Working memory (bytes) required. */ | ||
99 | "LZRW3", /* Name of algorithm. */ | ||
100 | "1.0", /* Version number of algorithm. */ | ||
101 | "31-Dec-1990", /* Date of algorithm. */ | ||
102 | "Public Domain", /* Copyright notice. */ | ||
103 | "Ross N. Williams", /* Author of algorithm. */ | ||
104 | "Renaissance Software", /* Affiliation of author. */ | ||
105 | "Public Domain" /* Vendor of algorithm. */ | ||
106 | }; | ||
107 | |||
108 | LOCAL void compress_compress (UBYTE *,UBYTE *,ULONG,UBYTE *, LONG *); | ||
109 | LOCAL void compress_decompress(UBYTE *,UBYTE *,LONG, UBYTE *, ULONG *); | ||
110 | |||
111 | /******************************************************************************/ | ||
112 | |||
113 | /* This function is the only function exported by this module. */ | ||
114 | /* Depending on its first parameter, the function can be requested to */ | ||
115 | /* compress a block of memory, decompress a block of memory, or to identify */ | ||
116 | /* itself. For more information, see the specification file "compress.h". */ | ||
117 | |||
118 | EXPORT void lzrw3_compress( | ||
119 | UWORD action, /* Action to be performed. */ | ||
120 | UBYTE *wrk_mem, /* Address of working memory we can use.*/ | ||
121 | UBYTE *src_adr, /* Address of input data. */ | ||
122 | LONG src_len, /* Length of input data. */ | ||
123 | UBYTE *dst_adr, /* Address to put output data. */ | ||
124 | void *p_dst_len /* Address of longword for length of output data.*/ | ||
125 | ) | ||
126 | { | ||
127 | switch (action) | ||
128 | { | ||
129 | case COMPRESS_ACTION_IDENTITY: | ||
130 | *((struct compress_identity **)p_dst_len)= &identity; | ||
131 | break; | ||
132 | case COMPRESS_ACTION_COMPRESS: | ||
133 | compress_compress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len); | ||
134 | break; | ||
135 | case COMPRESS_ACTION_DECOMPRESS: | ||
136 | compress_decompress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len); | ||
137 | break; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /******************************************************************************/ | ||
142 | /* */ | ||
143 | /* BRIEF DESCRIPTION OF THE LZRW3 ALGORITHM */ | ||
144 | /* ======================================== */ | ||
145 | /* The LZRW3 algorithm is identical to the LZRW1-A algorithm except that */ | ||
146 | /* instead of transmitting history offsets, it transmits hash table indexes. */ | ||
147 | /* In order to decode the indexes, the decompressor must maintain an */ | ||
148 | /* identical hash table. Copy items are straightforward:when the decompressor */ | ||
149 | /* receives a copy item, it simply looks up the hash table to translate the */ | ||
150 | /* index into a pointer into the data already decompressed. To update the */ | ||
151 | /* hash table, it replaces the same table entry with a pointer to the start */ | ||
152 | /* of the newly decoded phrase. The tricky part is with literal items, for at */ | ||
153 | /* the time that the decompressor receives a literal item the decompressor */ | ||
154 | /* does not have the three bytes in the Ziv (that the compressor has) to */ | ||
155 | /* perform the three-byte hash. To solve this problem, in LZRW3, both the */ | ||
156 | /* compressor and decompressor are wired up so that they "buffer" these */ | ||
157 | /* literals and update their hash tables only when three bytes are available. */ | ||
158 | /* This makes the maximum buffering 2 bytes. */ | ||
159 | /* */ | ||
160 | /* Replacement of offsets by hash table indexes yields a few percent extra */ | ||
161 | /* compression at the cost of some speed. LZRW3 is slower than LZRW1, LZRW1-A */ | ||
162 | /* and LZRW2, but yields better compression. */ | ||
163 | /* */ | ||
164 | /* Extra compression could be obtained by using a hash table of depth two. */ | ||
165 | /* However, increasing the depth above one incurs a significant decrease in */ | ||
166 | /* compression speed which was not considered worthwhile. Another reason for */ | ||
167 | /* keeping the depth down to one was to allow easy comparison with the */ | ||
168 | /* LZRW1-A and LZRW2 algorithms so as to demonstrate the exact effect of the */ | ||
169 | /* use of direct hash indexes. */ | ||
170 | /* */ | ||
171 | /* +---+ */ | ||
172 | /* |___|4095 */ | ||
173 | /* |___| */ | ||
174 | /* +---------------------*_|<---+ /----+---\ */ | ||
175 | /* | |___| +---|Hash | */ | ||
176 | /* | |___| |Function| */ | ||
177 | /* | |___| \--------/ */ | ||
178 | /* | |___|0 ^ */ | ||
179 | /* | +---+ | */ | ||
180 | /* | Hash +-----+ */ | ||
181 | /* | Table | */ | ||
182 | /* | --- */ | ||
183 | /* v ^^^ */ | ||
184 | /* +-------------------------------------|----------------+ */ | ||
185 | /* |||||||||||||||||||||||||||||||||||||||||||||||||||||||| */ | ||
186 | /* +-------------------------------------|----------------+ */ | ||
187 | /* | |1......18| | */ | ||
188 | /* |<------- Lempel=History ------------>|<--Ziv-->| | */ | ||
189 | /* | (=bytes already processed) |<-Still to go-->| */ | ||
190 | /* |<-------------------- INPUT BLOCK ------------------->| */ | ||
191 | /* */ | ||
192 | /* The diagram above for LZRW3 looks almost identical to the diagram for */ | ||
193 | /* LZRW1. The difference is that in LZRW3, the compressor transmits hash */ | ||
194 | /* table indices instead of Lempel offsets. For this to work, the */ | ||
195 | /* decompressor must maintain a hash table as well as the compressor and both */ | ||
196 | /* compressor and decompressor must "buffer" literals, as the decompressor */ | ||
197 | /* cannot hash phrases commencing with a literal until another two bytes have */ | ||
198 | /* arrived. */ | ||
199 | /* */ | ||
200 | /* LZRW3 Algorithm Execution Summary */ | ||
201 | /* --------------------------------- */ | ||
202 | /* 1. Hash the first three bytes of the Ziv to yield a hash table index h. */ | ||
203 | /* 2. Look up the hash table yielding history pointer p. */ | ||
204 | /* 3. Match where p points with the Ziv. If there is a match of three or */ | ||
205 | /* more bytes, code those bytes (in the Ziv) as a copy item, otherwise */ | ||
206 | /* code the next byte in the Ziv as a literal item. */ | ||
207 | /* 4. Update the hash table as possible subject to the constraint that only */ | ||
208 | /* phrases commencing three bytes back from the Ziv can be hashed and */ | ||
209 | /* entered into the hash table. (This enables the decompressor to keep */ | ||
210 | /* pace). See the description and code for more details. */ | ||
211 | /* */ | ||
212 | /******************************************************************************/ | ||
213 | /* */ | ||
214 | /* DEFINITION OF COMPRESSED FILE FORMAT */ | ||
215 | /* ==================================== */ | ||
216 | /* * A compressed file consists of a COPY FLAG followed by a REMAINDER. */ | ||
217 | /* * The copy flag CF uses up four bytes with the first byte being the */ | ||
218 | /* least significant. */ | ||
219 | /* * If CF=1, then the compressed file represents the remainder of the file */ | ||
220 | /* exactly. Otherwise CF=0 and the remainder of the file consists of zero */ | ||
221 | /* or more GROUPS, each of which represents one or more bytes. */ | ||
222 | /* * Each group consists of two bytes of CONTROL information followed by */ | ||
223 | /* sixteen ITEMs except for the last group which can contain from one */ | ||
224 | /* to sixteen items. */ | ||
225 | /* * An item can be either a LITERAL item or a COPY item. */ | ||
226 | /* * Each item corresponds to a bit in the control bytes. */ | ||
227 | /* * The first control byte corresponds to the first 8 items in the group */ | ||
228 | /* with bit 0 corresponding to the first item in the group and bit 7 to */ | ||
229 | /* the eighth item in the group. */ | ||
230 | /* * The second control byte corresponds to the second 8 items in the group */ | ||
231 | /* with bit 0 corresponding to the ninth item in the group and bit 7 to */ | ||
232 | /* the sixteenth item in the group. */ | ||
233 | /* * A zero bit in a control word means that the corresponding item is a */ | ||
234 | /* literal item. A one bit corresponds to a copy item. */ | ||
235 | /* * A literal item consists of a single byte which represents itself. */ | ||
236 | /* * A copy item consists of two bytes that represent from 3 to 18 bytes. */ | ||
237 | /* * The first byte in a copy item will be denoted C1. */ | ||
238 | /* * The second byte in a copy item will be denoted C2. */ | ||
239 | /* * Bits will be selected using square brackets. */ | ||
240 | /* For example: C1[0..3] is the low nibble of the first control byte. */ | ||
241 | /* of copy item C1. */ | ||
242 | /* * The LENGTH of a copy item is defined to be C1[0..3]+3 which is a number */ | ||
243 | /* in the range [3,18]. */ | ||
244 | /* * The INDEX of a copy item is defined to be C1[4..7]*256+C2[0..8] which */ | ||
245 | /* is a number in the range [0,4095]. */ | ||
246 | /* * A copy item represents the sequence of bytes */ | ||
247 | /* text[POS-OFFSET..POS-OFFSET+LENGTH-1] where */ | ||
248 | /* text is the entire text of the uncompressed string. */ | ||
249 | /* POS is the index in the text of the character following the */ | ||
250 | /* string represented by all the items preceeding the item */ | ||
251 | /* being defined. */ | ||
252 | /* OFFSET is obtained from INDEX by looking up the hash table. */ | ||
253 | /* */ | ||
254 | /******************************************************************************/ | ||
255 | |||
256 | /* The following #define defines the length of the copy flag that appears at */ | ||
257 | /* the start of the compressed file. The value of four bytes was chosen */ | ||
258 | /* because the fast_copy routine on my Macintosh runs faster if the source */ | ||
259 | /* and destination blocks are relatively longword aligned. */ | ||
260 | /* The actual flag data appears in the first byte. The rest are zeroed so as */ | ||
261 | /* to normalize the compressed representation (i.e. not non-deterministic). */ | ||
262 | #define FLAG_BYTES 4 | ||
263 | |||
264 | /* The following #defines define the meaning of the values of the copy */ | ||
265 | /* flag at the start of the compressed file. */ | ||
266 | #define FLAG_COMPRESS 0 /* Signals that output was result of compression. */ | ||
267 | #define FLAG_COPY 1 /* Signals that output was simply copied over. */ | ||
268 | |||
269 | /* The 68000 microprocessor (on which this algorithm was originally developed */ | ||
270 | /* is fussy about non-aligned arrays of words. To avoid these problems the */ | ||
271 | /* following macro can be used to "waste" from 0 to 3 bytes so as to align */ | ||
272 | /* the argument pointer. */ | ||
273 | #define ULONG_ALIGN_UP(X) ((((ULONG)X)+sizeof(ULONG)-1)&~(sizeof(ULONG)-1)) | ||
274 | |||
275 | |||
276 | /* The following constant defines the maximum length of an uncompressed item. */ | ||
277 | /* This definition must not be changed; its value is hardwired into the code. */ | ||
278 | /* The longest number of bytes that can be spanned by a single item is 18 */ | ||
279 | /* for the longest copy item. */ | ||
280 | #define MAX_RAW_ITEM (18) | ||
281 | |||
282 | /* The following constant defines the maximum length of an uncompressed group.*/ | ||
283 | /* This definition must not be changed; its value is hardwired into the code. */ | ||
284 | /* A group contains at most 16 items which explains this definition. */ | ||
285 | #define MAX_RAW_GROUP (16*MAX_RAW_ITEM) | ||
286 | |||
287 | /* The following constant defines the maximum length of a compressed group. */ | ||
288 | /* This definition must not be changed; its value is hardwired into the code. */ | ||
289 | /* A compressed group consists of two control bytes followed by up to 16 */ | ||
290 | /* compressed items each of which can have a maximum length of two bytes. */ | ||
291 | #define MAX_CMP_GROUP (2+16*2) | ||
292 | |||
293 | /* The following constant defines the number of entries in the hash table. */ | ||
294 | /* This definition must not be changed; its value is hardwired into the code. */ | ||
295 | #define HASH_TABLE_LENGTH (4096) | ||
296 | |||
297 | /* LZRW3, unlike LZRW1(-A), must initialize its hash table so as to enable */ | ||
298 | /* the compressor and decompressor to stay in step maintaining identical hash */ | ||
299 | /* tables. In an early version of the algorithm, the tables were simply */ | ||
300 | /* initialized to zero and a check for zero was included just before the */ | ||
301 | /* matching code. However, this test costs time. A better solution is to */ | ||
302 | /* initialize all the entries in the hash table to point to a constant */ | ||
303 | /* string. The decompressor does the same. This solution requires no extra */ | ||
304 | /* test. The contents of the string do not matter so long as the string is */ | ||
305 | /* the same for the compressor and decompressor and contains at least */ | ||
306 | /* MAX_RAW_ITEM bytes. I chose consecutive decimal digits because they do not */ | ||
307 | /* have white space problems (e.g. there is no chance that the compiler will */ | ||
308 | /* replace more than one space by a TAB) and because they make the length of */ | ||
309 | /* the string obvious by inspection. */ | ||
310 | #define START_STRING_18 ((UBYTE *) "123456789012345678") | ||
311 | |||
312 | /* In this algorithm, hash values have to be calculated at more than one */ | ||
313 | /* point. The following macro neatens the code up for this. */ | ||
314 | #define HASH(PTR) \ | ||
315 | (((40543*(((*(PTR))<<8)^((*((PTR)+1))<<4)^(*((PTR)+2))))>>4) & 0xFFF) | ||
316 | |||
317 | /******************************************************************************/ | ||
318 | |||
319 | /* Input : Hand over the required amount of working memory in p_wrk_mem. */ | ||
320 | /* Input : Specify input block using p_src_first and src_len. */ | ||
321 | /* Input : Point p_dst_first to the start of the output zone (OZ). */ | ||
322 | /* Input : Point p_dst_len to a ULONG to receive the output length. */ | ||
323 | /* Input : Input block and output zone must not overlap. */ | ||
324 | /* Output : Length of output block written to *p_dst_len. */ | ||
325 | /* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. May */ | ||
326 | /* Output : write in OZ=Mem[p_dst_first..p_dst_first+src_len+MAX_CMP_GROUP-1].*/ | ||
327 | /* Output : Upon completion guaranteed *p_dst_len<=src_len+FLAG_BYTES. */ | ||
328 | LOCAL void compress_compress(UBYTE *p_wrk_mem, | ||
329 | UBYTE *p_src_first, ULONG src_len, | ||
330 | UBYTE *p_dst_first, LONG *p_dst_len) | ||
331 | { | ||
332 | /* p_src and p_dst step through the source and destination blocks. */ | ||
333 | register UBYTE *p_src = p_src_first; | ||
334 | register UBYTE *p_dst = p_dst_first; | ||
335 | |||
336 | /* The following variables are never modified and are used in the */ | ||
337 | /* calculations that determine when the main loop terminates. */ | ||
338 | UBYTE *p_src_post = p_src_first+src_len; | ||
339 | UBYTE *p_dst_post = p_dst_first+src_len; | ||
340 | UBYTE *p_src_max1 = p_src_first+src_len-MAX_RAW_ITEM; | ||
341 | UBYTE *p_src_max16 = p_src_first+src_len-MAX_RAW_ITEM*16; | ||
342 | |||
343 | /* The variables 'p_control' and 'control' are used to buffer control bits. */ | ||
344 | /* Before each group is processed, the next two bytes of the output block */ | ||
345 | /* are set aside for the control word for the group about to be processed. */ | ||
346 | /* 'p_control' is set to point to the first byte of that word. Meanwhile, */ | ||
347 | /* 'control' buffers the control bits being generated during the processing */ | ||
348 | /* of the group. Instead of having a counter to keep track of how many items */ | ||
349 | /* have been processed (=the number of bits in the control word), at the */ | ||
350 | /* start of each group, the top word of 'control' is filled with 1 bits. */ | ||
351 | /* As 'control' is shifted for each item, the 1 bits in the top word are */ | ||
352 | /* absorbed or destroyed. When they all run out (i.e. when the top word is */ | ||
353 | /* all zero bits, we know that we are at the end of a group. */ | ||
354 | # define TOPWORD 0xFFFF0000 | ||
355 | UBYTE *p_control; | ||
356 | register ULONG control=TOPWORD; | ||
357 | |||
358 | /* THe variable 'hash' always points to the first element of the hash table. */ | ||
359 | UBYTE **hash= (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem); | ||
360 | |||
361 | /* The following two variables represent the literal buffer. p_h1 points to */ | ||
362 | /* the hash table entry corresponding to the youngest literal. p_h2 points */ | ||
363 | /* to the hash table entry corresponding to the second youngest literal. */ | ||
364 | /* Note: p_h1=0=>p_h2=0 because zero values denote absence of a pending */ | ||
365 | /* literal. The variables are initialized to zero meaning an empty "buffer". */ | ||
366 | UBYTE **p_h1=NULL; | ||
367 | UBYTE **p_h2=NULL; | ||
368 | |||
369 | /* To start, we write the flag bytes. Being optimistic, we set the flag to */ | ||
370 | /* FLAG_COMPRESS. The remaining flag bytes are zeroed so as to keep the */ | ||
371 | /* algorithm deterministic. */ | ||
372 | *p_dst++=FLAG_COMPRESS; | ||
373 | {UWORD i; for (i=2;i<=FLAG_BYTES;i++) *p_dst++=0;} | ||
374 | |||
375 | /* Reserve the first word of output as the control word for the first group. */ | ||
376 | /* Note: This is undone at the end if the input block is empty. */ | ||
377 | p_control=p_dst; p_dst+=2; | ||
378 | |||
379 | /* Initialize all elements of the hash table to point to a constant string. */ | ||
380 | /* Use of an unrolled loop speeds this up considerably. */ | ||
381 | {UWORD i; UBYTE **p_h=hash; | ||
382 | # define ZH *p_h++=START_STRING_18 | ||
383 | for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ | ||
384 | {ZH;ZH;ZH;ZH; | ||
385 | ZH;ZH;ZH;ZH; | ||
386 | ZH;ZH;ZH;ZH; | ||
387 | ZH;ZH;ZH;ZH;} | ||
388 | } | ||
389 | |||
390 | /* The main loop processes either 1 or 16 items per iteration. As its */ | ||
391 | /* termination logic is complicated, I have opted for an infinite loop */ | ||
392 | /* structure containing 'break' and 'goto' statements. */ | ||
393 | while (TRUE) | ||
394 | {/* Begin main processing loop. */ | ||
395 | |||
396 | /* Note: All the variables here except unroll should be defined within */ | ||
397 | /* the inner loop. Unfortunately the loop hasn't got a block. */ | ||
398 | register UBYTE *p; /* Scans through targ phrase during matching. */ | ||
399 | register UBYTE *p_ziv= NULL ; /* Points to first byte of current Ziv. */ | ||
400 | register UWORD unroll; /* Loop counter for unrolled inner loop. */ | ||
401 | register UWORD index; /* Index of current hash table entry. */ | ||
402 | register UBYTE **p_h0 = NULL ; /* Pointer to current hash table entry. */ | ||
403 | |||
404 | /* Test for overrun and jump to overrun code if necessary. */ | ||
405 | if (p_dst>p_dst_post) | ||
406 | goto overrun; | ||
407 | |||
408 | /* The following cascade of if statements efficiently catches and deals */ | ||
409 | /* with varying degrees of closeness to the end of the input block. */ | ||
410 | /* When we get very close to the end, we stop updating the table and */ | ||
411 | /* code the remaining bytes as literals. This makes the code simpler. */ | ||
412 | unroll=16; | ||
413 | if (p_src>p_src_max16) | ||
414 | { | ||
415 | unroll=1; | ||
416 | if (p_src>p_src_max1) | ||
417 | { | ||
418 | if (p_src==p_src_post) | ||
419 | break; | ||
420 | else | ||
421 | goto literal; | ||
422 | } | ||
423 | } | ||
424 | |||
425 | /* This inner unrolled loop processes 'unroll' (whose value is either 1 */ | ||
426 | /* or 16) items. I have chosen to implement this loop with labels and */ | ||
427 | /* gotos to heighten the ease with which the loop may be implemented with */ | ||
428 | /* a single decrement and branch instruction in assembly language and */ | ||
429 | /* also because the labels act as highly readable place markers. */ | ||
430 | /* (Also because we jump into the loop for endgame literals (see above)). */ | ||
431 | |||
432 | begin_unrolled_loop: | ||
433 | |||
434 | /* To process the next phrase, we hash the next three bytes and use */ | ||
435 | /* the resultant hash table index to look up the hash table. A pointer */ | ||
436 | /* to the entry is stored in p_h0 so as to avoid an array lookup. The */ | ||
437 | /* hash table entry *p_h0 is looked up yielding a pointer p to a */ | ||
438 | /* potential match of the Ziv in the history. */ | ||
439 | index=HASH(p_src); | ||
440 | p_h0=&hash[index]; | ||
441 | p=*p_h0; | ||
442 | |||
443 | /* Having looked up the candidate position, we are in a position to */ | ||
444 | /* attempt a match. The match loop has been unrolled using the PS */ | ||
445 | /* macro so that failure within the first three bytes automatically */ | ||
446 | /* results in the literal branch being taken. The coding is simple. */ | ||
447 | /* p_ziv saves p_src so we can let p_src wander. */ | ||
448 | # define PS *p++!=*p_src++ | ||
449 | p_ziv=p_src; | ||
450 | if (PS || PS || PS) | ||
451 | { | ||
452 | /* Literal. */ | ||
453 | |||
454 | /* Code the literal byte as itself and a zero control bit. */ | ||
455 | p_src=p_ziv; literal: *p_dst++=*p_src++; control&=0xFFFEFFFF; | ||
456 | |||
457 | /* We have just coded a literal. If we had two pending ones, that */ | ||
458 | /* makes three and we can update the hash table. */ | ||
459 | if (p_h2!=0) | ||
460 | {*p_h2=p_ziv-2;} | ||
461 | |||
462 | /* In any case, rotate the hash table pointers for next time. */ | ||
463 | p_h2=p_h1; p_h1=p_h0; | ||
464 | |||
465 | } | ||
466 | else | ||
467 | { | ||
468 | /* Copy */ | ||
469 | |||
470 | /* Match up to 15 remaining bytes using an unrolled loop and code. */ | ||
471 | #if 0 | ||
472 | PS || PS || PS || PS || PS || PS || PS || PS || | ||
473 | PS || PS || PS || PS || PS || PS || PS || p_src++; | ||
474 | #else | ||
475 | if ( | ||
476 | !( PS || PS || PS || PS || PS || PS || PS || PS || | ||
477 | PS || PS || PS || PS || PS || PS || PS ) | ||
478 | ) p_src++; | ||
479 | #endif | ||
480 | *p_dst++=((index&0xF00)>>4)|(--p_src-p_ziv-3); | ||
481 | *p_dst++=index&0xFF; | ||
482 | |||
483 | /* As we have just coded three bytes, we are now in a position to */ | ||
484 | /* update the hash table with the literal bytes that were pending */ | ||
485 | /* upon the arrival of extra context bytes. */ | ||
486 | if (p_h1!=0) | ||
487 | { | ||
488 | if (p_h2) | ||
489 | {*p_h2=p_ziv-2; p_h2=NULL;} | ||
490 | *p_h1=p_ziv-1; p_h1=NULL; | ||
491 | } | ||
492 | |||
493 | /* In any case, we can update the hash table based on the current */ | ||
494 | /* position as we just coded at least three bytes in a copy items. */ | ||
495 | *p_h0=p_ziv; | ||
496 | |||
497 | } | ||
498 | control>>=1; | ||
499 | |||
500 | /* This loop is all set up for a decrement and jump instruction! */ | ||
501 | #ifndef linux | ||
502 | ` end_unrolled_loop: if (--unroll) goto begin_unrolled_loop; | ||
503 | #else | ||
504 | /* end_unrolled_loop: */ if (--unroll) goto begin_unrolled_loop; | ||
505 | #endif | ||
506 | |||
507 | /* At this point it will nearly always be the end of a group in which */ | ||
508 | /* case, we have to do some control-word processing. However, near the */ | ||
509 | /* end of the input block, the inner unrolled loop is only executed once. */ | ||
510 | /* This necessitates the 'if' test. */ | ||
511 | if ((control&TOPWORD)==0) | ||
512 | { | ||
513 | /* Write the control word to the place we saved for it in the output. */ | ||
514 | *p_control++= control &0xFF; | ||
515 | *p_control = (control>>8) &0xFF; | ||
516 | |||
517 | /* Reserve the next word in the output block for the control word */ | ||
518 | /* for the group about to be processed. */ | ||
519 | p_control=p_dst; p_dst+=2; | ||
520 | |||
521 | /* Reset the control bits buffer. */ | ||
522 | control=TOPWORD; | ||
523 | } | ||
524 | |||
525 | } /* End main processing loop. */ | ||
526 | |||
527 | /* After the main processing loop has executed, all the input bytes have */ | ||
528 | /* been processed. However, the control word has still to be written to the */ | ||
529 | /* word reserved for it in the output at the start of the most recent group. */ | ||
530 | /* Before writing, the control word has to be shifted so that all the bits */ | ||
531 | /* are in the right place. The "empty" bit positions are filled with 1s */ | ||
532 | /* which partially fill the top word. */ | ||
533 | while(control&TOPWORD) control>>=1; | ||
534 | *p_control++= control &0xFF; | ||
535 | *p_control++=(control>>8) &0xFF; | ||
536 | |||
537 | /* If the last group contained no items, delete the control word too. */ | ||
538 | if (p_control==p_dst) p_dst-=2; | ||
539 | |||
540 | /* Write the length of the output block to the dst_len parameter and return. */ | ||
541 | *p_dst_len=p_dst-p_dst_first; | ||
542 | return; | ||
543 | |||
544 | /* Jump here as soon as an overrun is detected. An overrun is defined to */ | ||
545 | /* have occurred if p_dst>p_dst_first+src_len. That is, the moment the */ | ||
546 | /* length of the output written so far exceeds the length of the input block.*/ | ||
547 | /* The algorithm checks for overruns at least at the end of each group */ | ||
548 | /* which means that the maximum overrun is MAX_CMP_GROUP bytes. */ | ||
549 | /* Once an overrun occurs, the only thing to do is to set the copy flag and */ | ||
550 | /* copy the input over. */ | ||
551 | overrun: | ||
552 | #if 0 | ||
553 | *p_dst_first=FLAG_COPY; | ||
554 | fast_copy(p_src_first,p_dst_first+FLAG_BYTES,src_len); | ||
555 | *p_dst_len=src_len+FLAG_BYTES; | ||
556 | #else | ||
557 | fast_copy(p_src_first,p_dst_first,src_len); | ||
558 | *p_dst_len= -src_len; /* return a negative number to indicate uncompressed data */ | ||
559 | #endif | ||
560 | } | ||
561 | |||
562 | /******************************************************************************/ | ||
563 | |||
564 | /* Input : Hand over the required amount of working memory in p_wrk_mem. */ | ||
565 | /* Input : Specify input block using p_src_first and src_len. */ | ||
566 | /* Input : Point p_dst_first to the start of the output zone. */ | ||
567 | /* Input : Point p_dst_len to a ULONG to receive the output length. */ | ||
568 | /* Input : Input block and output zone must not overlap. User knows */ | ||
569 | /* Input : upperbound on output block length from earlier compression. */ | ||
570 | /* Input : In any case, maximum expansion possible is nine times. */ | ||
571 | /* Output : Length of output block written to *p_dst_len. */ | ||
572 | /* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */ | ||
573 | /* Output : Writes only in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */ | ||
574 | LOCAL void compress_decompress( UBYTE *p_wrk_mem, | ||
575 | UBYTE *p_src_first, LONG src_len, | ||
576 | UBYTE *p_dst_first, ULONG *p_dst_len) | ||
577 | { | ||
578 | /* Byte pointers p_src and p_dst scan through the input and output blocks. */ | ||
579 | register UBYTE *p_src = p_src_first+FLAG_BYTES; | ||
580 | register UBYTE *p_dst = p_dst_first; | ||
581 | /* we need to avoid a SEGV when trying to uncompress corrupt data */ | ||
582 | register UBYTE *p_dst_post = p_dst_first + *p_dst_len; | ||
583 | |||
584 | /* The following two variables are never modified and are used to control */ | ||
585 | /* the main loop. */ | ||
586 | UBYTE *p_src_post = p_src_first+src_len; | ||
587 | UBYTE *p_src_max16 = p_src_first+src_len-(MAX_CMP_GROUP-2); | ||
588 | |||
589 | /* The hash table is the only resident of the working memory. The hash table */ | ||
590 | /* contains HASH_TABLE_LENGTH=4096 pointers to positions in the history. To */ | ||
591 | /* keep Macintoshes happy, it is longword aligned. */ | ||
592 | UBYTE **hash = (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem); | ||
593 | |||
594 | /* The variable 'control' is used to buffer the control bits which appear in */ | ||
595 | /* groups of 16 bits (control words) at the start of each compressed group. */ | ||
596 | /* When each group is read, bit 16 of the register is set to one. Whenever */ | ||
597 | /* a new bit is needed, the register is shifted right. When the value of the */ | ||
598 | /* register becomes 1, we know that we have reached the end of a group. */ | ||
599 | /* Initializing the register to 1 thus instructs the code to follow that it */ | ||
600 | /* should read a new control word immediately. */ | ||
601 | register ULONG control=1; | ||
602 | |||
603 | /* The value of 'literals' is always in the range 0..3. It is the number of */ | ||
604 | /* consecutive literal items just seen. We have to record this number so as */ | ||
605 | /* to know when to update the hash table. When literals gets to 3, there */ | ||
606 | /* have been three consecutive literals and we can update at the position of */ | ||
607 | /* the oldest of the three. */ | ||
608 | register UWORD literals=0; | ||
609 | |||
610 | /* Check the leading copy flag to see if the compressor chose to use a copy */ | ||
611 | /* operation instead of a compression operation. If a copy operation was */ | ||
612 | /* used, then all we need to do is copy the data over, set the output length */ | ||
613 | /* and return. */ | ||
614 | #if 0 | ||
615 | if (*p_src_first==FLAG_COPY) | ||
616 | { | ||
617 | fast_copy(p_src_first+FLAG_BYTES,p_dst_first,src_len-FLAG_BYTES); | ||
618 | *p_dst_len=src_len-FLAG_BYTES; | ||
619 | return; | ||
620 | } | ||
621 | #else | ||
622 | if ( src_len < 0 ) | ||
623 | { | ||
624 | fast_copy(p_src_first,p_dst_first,-src_len ); | ||
625 | *p_dst_len = (ULONG)-src_len; | ||
626 | return; | ||
627 | } | ||
628 | #endif | ||
629 | |||
630 | /* Initialize all elements of the hash table to point to a constant string. */ | ||
631 | /* Use of an unrolled loop speeds this up considerably. */ | ||
632 | {UWORD i; UBYTE **p_h=hash; | ||
633 | # define ZJ *p_h++=START_STRING_18 | ||
634 | for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ | ||
635 | {ZJ;ZJ;ZJ;ZJ; | ||
636 | ZJ;ZJ;ZJ;ZJ; | ||
637 | ZJ;ZJ;ZJ;ZJ; | ||
638 | ZJ;ZJ;ZJ;ZJ;} | ||
639 | } | ||
640 | |||
641 | /* The outer loop processes either 1 or 16 items per iteration depending on */ | ||
642 | /* how close p_src is to the end of the input block. */ | ||
643 | while (p_src!=p_src_post) | ||
644 | {/* Start of outer loop */ | ||
645 | |||
646 | register UWORD unroll; /* Counts unrolled loop executions. */ | ||
647 | |||
648 | /* When 'control' has the value 1, it means that the 16 buffered control */ | ||
649 | /* bits that were read in at the start of the current group have all been */ | ||
650 | /* shifted out and that all that is left is the 1 bit that was injected */ | ||
651 | /* into bit 16 at the start of the current group. When we reach the end */ | ||
652 | /* of a group, we have to load a new control word and inject a new 1 bit. */ | ||
653 | if (control==1) | ||
654 | { | ||
655 | control=0x10000|*p_src++; | ||
656 | control|=(*p_src++)<<8; | ||
657 | } | ||
658 | |||
659 | /* If it is possible that we are within 16 groups from the end of the */ | ||
660 | /* input, execute the unrolled loop only once, else process a whole group */ | ||
661 | /* of 16 items by looping 16 times. */ | ||
662 | unroll= p_src<=p_src_max16 ? 16 : 1; | ||
663 | |||
664 | /* This inner loop processes one phrase (item) per iteration. */ | ||
665 | while (unroll--) | ||
666 | { /* Begin unrolled inner loop. */ | ||
667 | |||
668 | /* Process a literal or copy item depending on the next control bit. */ | ||
669 | if (control&1) | ||
670 | { | ||
671 | /* Copy item. */ | ||
672 | |||
673 | register UBYTE *p; /* Points to place from which to copy. */ | ||
674 | register UWORD lenmt; /* Length of copy item minus three. */ | ||
675 | register UBYTE **p_hte; /* Pointer to current hash table entry.*/ | ||
676 | register UBYTE *p_ziv=p_dst; /* Pointer to start of current Ziv. */ | ||
677 | |||
678 | /* Read and dismantle the copy word. Work out from where to copy. */ | ||
679 | lenmt=*p_src++; | ||
680 | p_hte=&hash[((lenmt&0xF0)<<4)|*p_src++]; | ||
681 | p=*p_hte; | ||
682 | lenmt&=0xF; | ||
683 | |||
684 | /* Now perform the copy using a half unrolled loop. */ | ||
685 | *p_dst++=*p++; | ||
686 | *p_dst++=*p++; | ||
687 | *p_dst++=*p++; | ||
688 | while (lenmt--) | ||
689 | *p_dst++=*p++; | ||
690 | |||
691 | /* Because we have just received 3 or more bytes in a copy item */ | ||
692 | /* (whose bytes we have just installed in the output), we are now */ | ||
693 | /* in a position to flush all the pending literal hashings that had */ | ||
694 | /* been postponed for lack of bytes. */ | ||
695 | if (literals>0) | ||
696 | { | ||
697 | register UBYTE *r=p_ziv-literals; | ||
698 | hash[HASH(r)]=r; | ||
699 | if (literals==2) | ||
700 | {r++; hash[HASH(r)]=r;} | ||
701 | literals=0; | ||
702 | } | ||
703 | |||
704 | /* In any case, we can immediately update the hash table with the */ | ||
705 | /* current position. We don't need to do a HASH(...) to work out */ | ||
706 | /* where to put the pointer, as the compressor just told us!!! */ | ||
707 | *p_hte=p_ziv; | ||
708 | |||
709 | } | ||
710 | else | ||
711 | { | ||
712 | /* Literal item. */ | ||
713 | |||
714 | /* Copy over the literal byte. */ | ||
715 | *p_dst++=*p_src++; | ||
716 | |||
717 | /* If we now have three literals waiting to be hashed into the hash */ | ||
718 | /* table, we can do one of them now (because there are three). */ | ||
719 | if (++literals == 3) | ||
720 | {register UBYTE *p=p_dst-3; hash[HASH(p)]=p; literals=2;} | ||
721 | } | ||
722 | |||
723 | /* Shift the control buffer so the next control bit is in bit 0. */ | ||
724 | control>>=1; | ||
725 | #if 1 | ||
726 | if (p_dst > p_dst_post) | ||
727 | { | ||
728 | /* Shit: we tried to decompress corrupt data */ | ||
729 | *p_dst_len = 0; | ||
730 | return; | ||
731 | } | ||
732 | #endif | ||
733 | } /* End unrolled inner loop. */ | ||
734 | |||
735 | } /* End of outer loop */ | ||
736 | |||
737 | /* Write the length of the decompressed data before returning. */ | ||
738 | *p_dst_len=p_dst-p_dst_first; | ||
739 | } | ||
740 | |||
741 | /******************************************************************************/ | ||
742 | /* End of LZRW3.C */ | ||
743 | /******************************************************************************/ | ||
diff --git a/drivers/char/ftape/compressor/lzrw3.h b/drivers/char/ftape/compressor/lzrw3.h deleted file mode 100644 index 533feba47526..000000000000 --- a/drivers/char/ftape/compressor/lzrw3.h +++ /dev/null | |||
@@ -1,253 +0,0 @@ | |||
1 | #ifndef _LZRW3_H | ||
2 | #define _LZRW3_H | ||
3 | /* | ||
4 | * $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.h,v $ | ||
5 | * $Revision: 1.1 $ | ||
6 | * $Date: 1997/10/05 19:12:30 $ | ||
7 | * | ||
8 | * include files for lzrw3. Only slighty modified from the original | ||
9 | * version. Assembles the three include files compress.h, port.h and | ||
10 | * fastcopy.h from the original lzrw3 package. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | #include <linux/string.h> | ||
16 | |||
17 | /******************************************************************************/ | ||
18 | /* */ | ||
19 | /* COMPRESS.H */ | ||
20 | /* */ | ||
21 | /******************************************************************************/ | ||
22 | /* */ | ||
23 | /* Author : Ross Williams. */ | ||
24 | /* Date : December 1989. */ | ||
25 | /* */ | ||
26 | /* This header file defines the interface to a set of functions called */ | ||
27 | /* 'compress', each member of which implements a particular data compression */ | ||
28 | /* algorithm. */ | ||
29 | /* */ | ||
30 | /* Normally in C programming, for each .H file, there is a corresponding .C */ | ||
31 | /* file that implements the functions promised in the .H file. */ | ||
32 | /* Here, there are many .C files corresponding to this header file. */ | ||
33 | /* Each comforming implementation file contains a single function */ | ||
34 | /* called 'compress' that implements a single data compression */ | ||
35 | /* algorithm that conforms with the interface specified in this header file. */ | ||
36 | /* Only one algorithm can be linked in at a time in this organization. */ | ||
37 | /* */ | ||
38 | /******************************************************************************/ | ||
39 | /* */ | ||
40 | /* DEFINITION OF FUNCTION COMPRESS */ | ||
41 | /* =============================== */ | ||
42 | /* */ | ||
43 | /* Summary of Function Compress */ | ||
44 | /* ---------------------------- */ | ||
45 | /* The action that 'compress' takes depends on its first argument called */ | ||
46 | /* 'action'. The function provides three actions: */ | ||
47 | /* */ | ||
48 | /* - Return information about the algorithm. */ | ||
49 | /* - Compress a block of memory. */ | ||
50 | /* - Decompress a block of memory. */ | ||
51 | /* */ | ||
52 | /* Parameters */ | ||
53 | /* ---------- */ | ||
54 | /* See the formal C definition later for a description of the parameters. */ | ||
55 | /* */ | ||
56 | /* Constants */ | ||
57 | /* --------- */ | ||
58 | /* COMPRESS_OVERRUN: The constant COMPRESS_OVERRUN defines by how many bytes */ | ||
59 | /* an algorithm is allowed to expand a block during a compression operation. */ | ||
60 | /* */ | ||
61 | /* Although compression algorithms usually compress data, there will always */ | ||
62 | /* be data that a given compressor will expand (this can be proven). */ | ||
63 | /* Fortunately, the degree of expansion can be limited to a single bit, by */ | ||
64 | /* copying over the input data if the data gets bigger during compression. */ | ||
65 | /* To allow for this possibility, the first bit of a compressed */ | ||
66 | /* representation can be used as a flag indicating whether the */ | ||
67 | /* input data was copied over, or truly compressed. In practice, the first */ | ||
68 | /* byte would be used to store this bit so as to maintain byte alignment. */ | ||
69 | /* */ | ||
70 | /* Unfortunately, in general, the only way to tell if an algorithm will */ | ||
71 | /* expand a particular block of data is to run the algorithm on the data. */ | ||
72 | /* If the algorithm does not continuously monitor how many output bytes it */ | ||
73 | /* has written, it might write an output block far larger than the input */ | ||
74 | /* block before realizing that it has done so. */ | ||
75 | /* On the other hand, continuous checks on output length are inefficient. */ | ||
76 | /* */ | ||
77 | /* To cater for all these problems, this interface definition: */ | ||
78 | /* > Allows a compression algorithm to return an output block that is up to */ | ||
79 | /* COMPRESS_OVERRUN bytes longer than the input block. */ | ||
80 | /* > Allows a compression algorithm to write up to COMPRESS_OVERRUN bytes */ | ||
81 | /* more than the length of the input block to the memory of the output */ | ||
82 | /* block regardless of the length of the output block eventually returned. */ | ||
83 | /* This allows an algorithm to overrun the length of the input block in the */ | ||
84 | /* output block by up to COMPRESS_OVERRUN bytes between expansion checks. */ | ||
85 | /* */ | ||
86 | /* The problem does not arise for decompression. */ | ||
87 | /* */ | ||
88 | /* Identity Action */ | ||
89 | /* --------------- */ | ||
90 | /* > action must be COMPRESS_ACTION_IDENTITY. */ | ||
91 | /* > p_dst_len must point to a longword to receive a longword address. */ | ||
92 | /* > The value of the other parameters does not matter. */ | ||
93 | /* > After execution, the longword that p_dst_len points to will be a pointer */ | ||
94 | /* to a structure of type compress_identity. */ | ||
95 | /* Thus, for example, after the call, (*p_dst_len)->memory will return the */ | ||
96 | /* number of bytes of working memory that the algorithm requires to run. */ | ||
97 | /* > The values of the identity structure returned are fixed constant */ | ||
98 | /* attributes of the algorithm and must not vary from call to call. */ | ||
99 | /* */ | ||
100 | /* Common Requirements for Compression and Decompression Actions */ | ||
101 | /* ------------------------------------------------------------- */ | ||
102 | /* > wrk_mem must point to an unused block of memory of a length specified in */ | ||
103 | /* the algorithm's identity block. The identity block can be obtained by */ | ||
104 | /* making a separate call to compress, specifying the identity action. */ | ||
105 | /* > The INPUT BLOCK is defined to be Memory[src_addr,src_addr+src_len-1]. */ | ||
106 | /* > dst_len will be used to denote *p_dst_len. */ | ||
107 | /* > dst_len is not read by compress, only written. */ | ||
108 | /* > The value of dst_len is defined only upon termination. */ | ||
109 | /* > The OUTPUT BLOCK is defined to be Memory[dst_addr,dst_addr+dst_len-1]. */ | ||
110 | /* */ | ||
111 | /* Compression Action */ | ||
112 | /* ------------------ */ | ||
113 | /* > action must be COMPRESS_ACTION_COMPRESS. */ | ||
114 | /* > src_len must be in the range [0,COMPRESS_MAX_ORG]. */ | ||
115 | /* > The OUTPUT ZONE is defined to be */ | ||
116 | /* Memory[dst_addr,dst_addr+src_len-1+COMPRESS_OVERRUN]. */ | ||
117 | /* > The function can modify any part of the output zone regardless of the */ | ||
118 | /* final length of the output block. */ | ||
119 | /* > The input block and the output zone must not overlap. */ | ||
120 | /* > dst_len will be in the range [0,src_len+COMPRESS_OVERRUN]. */ | ||
121 | /* > dst_len will be in the range [0,COMPRESS_MAX_COM] (from prev fact). */ | ||
122 | /* > The output block will consist of a representation of the input block. */ | ||
123 | /* */ | ||
124 | /* Decompression Action */ | ||
125 | /* -------------------- */ | ||
126 | /* > action must be COMPRESS_ACTION_DECOMPRESS. */ | ||
127 | /* > The input block must be the result of an earlier compression operation. */ | ||
128 | /* > If the previous fact is true, the following facts must also be true: */ | ||
129 | /* > src_len will be in the range [0,COMPRESS_MAX_COM]. */ | ||
130 | /* > dst_len will be in the range [0,COMPRESS_MAX_ORG]. */ | ||
131 | /* > The input and output blocks must not overlap. */ | ||
132 | /* > Only the output block is modified. */ | ||
133 | /* > Upon termination, the output block will consist of the bytes contained */ | ||
134 | /* in the input block passed to the earlier compression operation. */ | ||
135 | /* */ | ||
136 | /******************************************************************************/ | ||
137 | |||
138 | /******************************************************************************/ | ||
139 | /* */ | ||
140 | /* PORT.H */ | ||
141 | /* */ | ||
142 | /******************************************************************************/ | ||
143 | /* */ | ||
144 | /* This module contains macro definitions and types that are likely to */ | ||
145 | /* change between computers. */ | ||
146 | /* */ | ||
147 | /******************************************************************************/ | ||
148 | |||
149 | #ifndef DONE_PORT /* Only do this if not previously done. */ | ||
150 | |||
151 | #ifdef THINK_C | ||
152 | #define UBYTE unsigned char /* Unsigned byte */ | ||
153 | #define UWORD unsigned int /* Unsigned word (2 bytes) */ | ||
154 | #define ULONG unsigned long /* Unsigned word (4 bytes) */ | ||
155 | #define BOOL unsigned char /* Boolean */ | ||
156 | #define FOPEN_BINARY_READ "rb" /* Mode string for binary reading. */ | ||
157 | #define FOPEN_BINARY_WRITE "wb" /* Mode string for binary writing. */ | ||
158 | #define FOPEN_TEXT_APPEND "a" /* Mode string for text appending. */ | ||
159 | #define REAL double /* USed for floating point stuff. */ | ||
160 | #endif | ||
161 | #if defined(LINUX) || defined(linux) | ||
162 | #define UBYTE __u8 /* Unsigned byte */ | ||
163 | #define UWORD __u16 /* Unsigned word (2 bytes) */ | ||
164 | #define ULONG __u32 /* Unsigned word (4 bytes) */ | ||
165 | #define LONG __s32 /* Signed word (4 bytes) */ | ||
166 | #define BOOL is not used here /* Boolean */ | ||
167 | #define FOPEN_BINARY_READ not used /* Mode string for binary reading. */ | ||
168 | #define FOPEN_BINARY_WRITE not used /* Mode string for binary writing. */ | ||
169 | #define FOPEN_TEXT_APPEND not used /* Mode string for text appending. */ | ||
170 | #define REAL not used /* USed for floating point stuff. */ | ||
171 | #ifndef TRUE | ||
172 | #define TRUE 1 | ||
173 | #endif | ||
174 | #endif | ||
175 | |||
176 | #define DONE_PORT /* Don't do all this again. */ | ||
177 | #define MALLOC_FAIL NULL /* Failure status from malloc() */ | ||
178 | #define LOCAL static /* For non-exported routines. */ | ||
179 | #define EXPORT /* Signals exported function. */ | ||
180 | #define then /* Useful for aligning ifs. */ | ||
181 | |||
182 | #endif | ||
183 | |||
184 | /******************************************************************************/ | ||
185 | /* End of PORT.H */ | ||
186 | /******************************************************************************/ | ||
187 | |||
188 | #define COMPRESS_ACTION_IDENTITY 0 | ||
189 | #define COMPRESS_ACTION_COMPRESS 1 | ||
190 | #define COMPRESS_ACTION_DECOMPRESS 2 | ||
191 | |||
192 | #define COMPRESS_OVERRUN 1024 | ||
193 | #define COMPRESS_MAX_COM 0x70000000 | ||
194 | #define COMPRESS_MAX_ORG (COMPRESS_MAX_COM-COMPRESS_OVERRUN) | ||
195 | |||
196 | #define COMPRESS_MAX_STRLEN 255 | ||
197 | |||
198 | /* The following structure provides information about the algorithm. */ | ||
199 | /* > The top bit of id must be zero. The remaining bits must be chosen by */ | ||
200 | /* the author of the algorithm by tossing a coin 31 times. */ | ||
201 | /* > The amount of memory requested by the algorithm is specified in bytes */ | ||
202 | /* and must be in the range [0,0x70000000]. */ | ||
203 | /* > All strings s must be such that strlen(s)<=COMPRESS_MAX_STRLEN. */ | ||
204 | struct compress_identity | ||
205 | { | ||
206 | ULONG id; /* Identifying number of algorithm. */ | ||
207 | ULONG memory; /* Number of bytes of working memory required. */ | ||
208 | |||
209 | char *name; /* Name of algorithm. */ | ||
210 | char *version; /* Version number. */ | ||
211 | char *date; /* Date of release of this version. */ | ||
212 | char *copyright; /* Copyright message. */ | ||
213 | |||
214 | char *author; /* Author of algorithm. */ | ||
215 | char *affiliation; /* Affiliation of author. */ | ||
216 | char *vendor; /* Where the algorithm can be obtained. */ | ||
217 | }; | ||
218 | |||
219 | void lzrw3_compress( /* Single function interface to compression algorithm. */ | ||
220 | UWORD action, /* Action to be performed. */ | ||
221 | UBYTE *wrk_mem, /* Working memory temporarily given to routine to use. */ | ||
222 | UBYTE *src_adr, /* Address of input data. */ | ||
223 | LONG src_len, /* Length of input data. */ | ||
224 | UBYTE *dst_adr, /* Address of output data. */ | ||
225 | void *p_dst_len /* Pointer to a longword where routine will write: */ | ||
226 | /* If action=..IDENTITY => Adr of id structure. */ | ||
227 | /* If action=..COMPRESS => Length of output data. */ | ||
228 | /* If action=..DECOMPRESS => Length of output data. */ | ||
229 | ); | ||
230 | |||
231 | /******************************************************************************/ | ||
232 | /* End of COMPRESS.H */ | ||
233 | /******************************************************************************/ | ||
234 | |||
235 | |||
236 | /******************************************************************************/ | ||
237 | /* fast_copy.h */ | ||
238 | /******************************************************************************/ | ||
239 | |||
240 | /* This function copies a block of memory very quickly. */ | ||
241 | /* The exact speed depends on the relative alignment of the blocks of memory. */ | ||
242 | /* PRE : 0<=src_len<=(2^32)-1 . */ | ||
243 | /* PRE : Source and destination blocks must not overlap. */ | ||
244 | /* POST : MEM[dst_adr,dst_adr+src_len-1]=MEM[src_adr,src_adr+src_len-1]. */ | ||
245 | /* POST : MEM[dst_adr,dst_adr+src_len-1] is the only memory changed. */ | ||
246 | |||
247 | #define fast_copy(src,dst,len) memcpy(dst,src,len) | ||
248 | |||
249 | /******************************************************************************/ | ||
250 | /* End of fast_copy.h */ | ||
251 | /******************************************************************************/ | ||
252 | |||
253 | #endif | ||
diff --git a/drivers/char/ftape/compressor/zftape-compress.c b/drivers/char/ftape/compressor/zftape-compress.c deleted file mode 100644 index 65ffc0be3df9..000000000000 --- a/drivers/char/ftape/compressor/zftape-compress.c +++ /dev/null | |||
@@ -1,1203 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1994-1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU General Public License as | ||
6 | published by the Free Software Foundation; either version 2, or (at | ||
7 | your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, but | ||
10 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | 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, | ||
17 | USA. | ||
18 | |||
19 | * | ||
20 | * This file implements a "generic" interface between the * | ||
21 | * zftape-driver and a compression-algorithm. The * | ||
22 | * compression-algorithm currently used is a LZ77. I use the * | ||
23 | * implementation lzrw3 by Ross N. Williams (Renaissance * | ||
24 | * Software). The compression program itself is in the file | ||
25 | * lzrw3.c * and lzrw3.h. To adopt another compression algorithm | ||
26 | * the functions * zft_compress() and zft_uncompress() must be | ||
27 | * changed * appropriately. See below. | ||
28 | */ | ||
29 | |||
30 | #include <linux/errno.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/module.h> | ||
33 | |||
34 | #include <linux/zftape.h> | ||
35 | |||
36 | #include <asm/uaccess.h> | ||
37 | |||
38 | #include "../zftape/zftape-init.h" | ||
39 | #include "../zftape/zftape-eof.h" | ||
40 | #include "../zftape/zftape-ctl.h" | ||
41 | #include "../zftape/zftape-write.h" | ||
42 | #include "../zftape/zftape-read.h" | ||
43 | #include "../zftape/zftape-rw.h" | ||
44 | #include "../compressor/zftape-compress.h" | ||
45 | #include "../zftape/zftape-vtbl.h" | ||
46 | #include "../compressor/lzrw3.h" | ||
47 | |||
48 | /* | ||
49 | * global variables | ||
50 | */ | ||
51 | |||
52 | /* I handle the allocation of this buffer as a special case, because | ||
53 | * it's size varies depending on the tape length inserted. | ||
54 | */ | ||
55 | |||
56 | /* local variables | ||
57 | */ | ||
58 | static void *zftc_wrk_mem = NULL; | ||
59 | static __u8 *zftc_buf = NULL; | ||
60 | static void *zftc_scratch_buf = NULL; | ||
61 | |||
62 | /* compression statistics | ||
63 | */ | ||
64 | static unsigned int zftc_wr_uncompressed = 0; | ||
65 | static unsigned int zftc_wr_compressed = 0; | ||
66 | static unsigned int zftc_rd_uncompressed = 0; | ||
67 | static unsigned int zftc_rd_compressed = 0; | ||
68 | |||
69 | /* forward */ | ||
70 | static int zftc_write(int *write_cnt, | ||
71 | __u8 *dst_buf, const int seg_sz, | ||
72 | const __u8 __user *src_buf, const int req_len, | ||
73 | const zft_position *pos, const zft_volinfo *volume); | ||
74 | static int zftc_read(int *read_cnt, | ||
75 | __u8 __user *dst_buf, const int to_do, | ||
76 | const __u8 *src_buf, const int seg_sz, | ||
77 | const zft_position *pos, const zft_volinfo *volume); | ||
78 | static int zftc_seek(unsigned int new_block_pos, | ||
79 | zft_position *pos, const zft_volinfo *volume, | ||
80 | __u8 *buffer); | ||
81 | static void zftc_lock (void); | ||
82 | static void zftc_reset (void); | ||
83 | static void zftc_cleanup(void); | ||
84 | static void zftc_stats (void); | ||
85 | |||
86 | /* compressed segment. This conforms to QIC-80-MC, Revision K. | ||
87 | * | ||
88 | * Rev. K applies to tapes with `fixed length format' which is | ||
89 | * indicated by format code 2,3 and 5. See below for format code 4 and 6 | ||
90 | * | ||
91 | * 2 bytes: offset of compression segment structure | ||
92 | * 29k > offset >= 29k-18: data from previous segment ens in this | ||
93 | * segment and no compressed block starts | ||
94 | * in this segment | ||
95 | * offset == 0: data from previous segment occupies entire | ||
96 | * segment and continues in next segment | ||
97 | * n bytes: remainder from previous segment | ||
98 | * | ||
99 | * Rev. K: | ||
100 | * 4 bytes: 4 bytes: files set byte offset | ||
101 | * Post Rev. K and QIC-3020/3020: | ||
102 | * 8 bytes: 8 bytes: files set byte offset | ||
103 | * 2 bytes: byte count N (amount of data following) | ||
104 | * bit 15 is set if data is compressed, bit 15 is not | ||
105 | * set if data is uncompressed | ||
106 | * N bytes: data (as much as specified in the byte count) | ||
107 | * 2 bytes: byte count N_1 of next cluster | ||
108 | * N_1 bytes: data of next cluset | ||
109 | * 2 bytes: byte count N_2 of next cluster | ||
110 | * N_2 bytes: ... | ||
111 | * | ||
112 | * Note that the `N' byte count accounts only for the bytes that in the | ||
113 | * current segment if the cluster spans to the next segment. | ||
114 | */ | ||
115 | |||
116 | typedef struct | ||
117 | { | ||
118 | int cmpr_pos; /* actual position in compression buffer */ | ||
119 | int cmpr_sz; /* what is left in the compression buffer | ||
120 | * when copying the compressed data to the | ||
121 | * deblock buffer | ||
122 | */ | ||
123 | unsigned int first_block; /* location of header information in | ||
124 | * this segment | ||
125 | */ | ||
126 | unsigned int count; /* amount of data of current block | ||
127 | * contained in current segment | ||
128 | */ | ||
129 | unsigned int offset; /* offset in current segment */ | ||
130 | unsigned int spans:1; /* might continue in next segment */ | ||
131 | unsigned int uncmpr; /* 0x8000 if this block contains | ||
132 | * uncompressed data | ||
133 | */ | ||
134 | __s64 foffs; /* file set byte offset, same as in | ||
135 | * compression map segment | ||
136 | */ | ||
137 | } cmpr_info; | ||
138 | |||
139 | static cmpr_info cseg; /* static data. Must be kept uptodate and shared by | ||
140 | * read, write and seek functions | ||
141 | */ | ||
142 | |||
143 | #define DUMP_CMPR_INFO(level, msg, info) \ | ||
144 | TRACE(level, msg "\n" \ | ||
145 | KERN_INFO "cmpr_pos : %d\n" \ | ||
146 | KERN_INFO "cmpr_sz : %d\n" \ | ||
147 | KERN_INFO "first_block: %d\n" \ | ||
148 | KERN_INFO "count : %d\n" \ | ||
149 | KERN_INFO "offset : %d\n" \ | ||
150 | KERN_INFO "spans : %d\n" \ | ||
151 | KERN_INFO "uncmpr : 0x%04x\n" \ | ||
152 | KERN_INFO "foffs : " LL_X, \ | ||
153 | (info)->cmpr_pos, (info)->cmpr_sz, (info)->first_block, \ | ||
154 | (info)->count, (info)->offset, (info)->spans == 1, \ | ||
155 | (info)->uncmpr, LL((info)->foffs)) | ||
156 | |||
157 | /* dispatch compression segment info, return error code | ||
158 | * | ||
159 | * afterwards, cseg->offset points to start of data of the NEXT | ||
160 | * compressed block, and cseg->count contains the amount of data | ||
161 | * left in the actual compressed block. cseg->spans is set to 1 if | ||
162 | * the block is continued in the following segment. Otherwise it is | ||
163 | * set to 0. | ||
164 | */ | ||
165 | static int get_cseg (cmpr_info *cinfo, const __u8 *buff, | ||
166 | const unsigned int seg_sz, | ||
167 | const zft_volinfo *volume) | ||
168 | { | ||
169 | TRACE_FUN(ft_t_flow); | ||
170 | |||
171 | cinfo->first_block = GET2(buff, 0); | ||
172 | if (cinfo->first_block == 0) { /* data spans to next segment */ | ||
173 | cinfo->count = seg_sz - sizeof(__u16); | ||
174 | cinfo->offset = seg_sz; | ||
175 | cinfo->spans = 1; | ||
176 | } else { /* cluster definetely ends in this segment */ | ||
177 | if (cinfo->first_block > seg_sz) { | ||
178 | /* data corrupted */ | ||
179 | TRACE_ABORT(-EIO, ft_t_err, "corrupted data:\n" | ||
180 | KERN_INFO "segment size: %d\n" | ||
181 | KERN_INFO "first block : %d", | ||
182 | seg_sz, cinfo->first_block); | ||
183 | } | ||
184 | cinfo->count = cinfo->first_block - sizeof(__u16); | ||
185 | cinfo->offset = cinfo->first_block; | ||
186 | cinfo->spans = 0; | ||
187 | } | ||
188 | /* now get the offset the first block should have in the | ||
189 | * uncompressed data stream. | ||
190 | * | ||
191 | * For this magic `18' refer to CRF-3 standard or QIC-80MC, | ||
192 | * Rev. K. | ||
193 | */ | ||
194 | if ((seg_sz - cinfo->offset) > 18) { | ||
195 | if (volume->qic113) { /* > revision K */ | ||
196 | TRACE(ft_t_data_flow, "New QIC-113 compliance"); | ||
197 | cinfo->foffs = GET8(buff, cinfo->offset); | ||
198 | cinfo->offset += sizeof(__s64); | ||
199 | } else { | ||
200 | TRACE(/* ft_t_data_flow */ ft_t_noise, "pre QIC-113 version"); | ||
201 | cinfo->foffs = (__s64)GET4(buff, cinfo->offset); | ||
202 | cinfo->offset += sizeof(__u32); | ||
203 | } | ||
204 | } | ||
205 | if (cinfo->foffs > volume->size) { | ||
206 | TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n" | ||
207 | KERN_INFO "offset in current volume: %d\n" | ||
208 | KERN_INFO "size of current volume : %d", | ||
209 | (int)(cinfo->foffs>>10), (int)(volume->size>>10)); | ||
210 | } | ||
211 | if (cinfo->cmpr_pos + cinfo->count > volume->blk_sz) { | ||
212 | TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n" | ||
213 | KERN_INFO "block size : %d\n" | ||
214 | KERN_INFO "data record: %d", | ||
215 | volume->blk_sz, cinfo->cmpr_pos + cinfo->count); | ||
216 | } | ||
217 | DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", cinfo); | ||
218 | TRACE_EXIT 0; | ||
219 | } | ||
220 | |||
221 | /* This one is called, when a new cluster starts in same segment. | ||
222 | * | ||
223 | * Note: if this is the first cluster in the current segment, we must | ||
224 | * not check whether there are more than 18 bytes available because | ||
225 | * this have already been done in get_cseg() and there may be less | ||
226 | * than 18 bytes available due to header information. | ||
227 | * | ||
228 | */ | ||
229 | static void get_next_cluster(cmpr_info *cluster, const __u8 *buff, | ||
230 | const int seg_sz, const int finish) | ||
231 | { | ||
232 | TRACE_FUN(ft_t_flow); | ||
233 | |||
234 | if (seg_sz - cluster->offset > 18 || cluster->foffs != 0) { | ||
235 | cluster->count = GET2(buff, cluster->offset); | ||
236 | cluster->uncmpr = cluster->count & 0x8000; | ||
237 | cluster->count -= cluster->uncmpr; | ||
238 | cluster->offset += sizeof(__u16); | ||
239 | cluster->foffs = 0; | ||
240 | if ((cluster->offset + cluster->count) < seg_sz) { | ||
241 | cluster->spans = 0; | ||
242 | } else if (cluster->offset + cluster->count == seg_sz) { | ||
243 | cluster->spans = !finish; | ||
244 | } else { | ||
245 | /* either an error or a volume written by an | ||
246 | * old version. If this is a data error, then we'll | ||
247 | * catch it later. | ||
248 | */ | ||
249 | TRACE(ft_t_data_flow, "Either error or old volume"); | ||
250 | cluster->spans = 1; | ||
251 | cluster->count = seg_sz - cluster->offset; | ||
252 | } | ||
253 | } else { | ||
254 | cluster->count = 0; | ||
255 | cluster->spans = 0; | ||
256 | cluster->foffs = 0; | ||
257 | } | ||
258 | DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */ , "", cluster); | ||
259 | TRACE_EXIT; | ||
260 | } | ||
261 | |||
262 | static void zftc_lock(void) | ||
263 | { | ||
264 | } | ||
265 | |||
266 | /* this function is needed for zftape_reset_position in zftape-io.c | ||
267 | */ | ||
268 | static void zftc_reset(void) | ||
269 | { | ||
270 | TRACE_FUN(ft_t_flow); | ||
271 | |||
272 | memset((void *)&cseg, '\0', sizeof(cseg)); | ||
273 | zftc_stats(); | ||
274 | TRACE_EXIT; | ||
275 | } | ||
276 | |||
277 | static int cmpr_mem_initialized = 0; | ||
278 | static unsigned int alloc_blksz = 0; | ||
279 | |||
280 | static int zft_allocate_cmpr_mem(unsigned int blksz) | ||
281 | { | ||
282 | TRACE_FUN(ft_t_flow); | ||
283 | |||
284 | if (cmpr_mem_initialized && blksz == alloc_blksz) { | ||
285 | TRACE_EXIT 0; | ||
286 | } | ||
287 | TRACE_CATCH(zft_vmalloc_once(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE), | ||
288 | zftc_cleanup()); | ||
289 | TRACE_CATCH(zft_vmalloc_always(&zftc_buf, blksz + CMPR_OVERRUN), | ||
290 | zftc_cleanup()); | ||
291 | alloc_blksz = blksz; | ||
292 | TRACE_CATCH(zft_vmalloc_always(&zftc_scratch_buf, blksz+CMPR_OVERRUN), | ||
293 | zftc_cleanup()); | ||
294 | cmpr_mem_initialized = 1; | ||
295 | TRACE_EXIT 0; | ||
296 | } | ||
297 | |||
298 | static void zftc_cleanup(void) | ||
299 | { | ||
300 | TRACE_FUN(ft_t_flow); | ||
301 | |||
302 | zft_vfree(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE); | ||
303 | zft_vfree(&zftc_buf, alloc_blksz + CMPR_OVERRUN); | ||
304 | zft_vfree(&zftc_scratch_buf, alloc_blksz + CMPR_OVERRUN); | ||
305 | cmpr_mem_initialized = alloc_blksz = 0; | ||
306 | TRACE_EXIT; | ||
307 | } | ||
308 | |||
309 | /***************************************************************************** | ||
310 | * * | ||
311 | * The following two functions "ftape_compress()" and * | ||
312 | * "ftape_uncompress()" are the interface to the actual compression * | ||
313 | * algorithm (i.e. they are calling the "compress()" function from * | ||
314 | * the lzrw3 package for now). These routines could quite easily be * | ||
315 | * changed to adopt another compression algorithm instead of lzrw3, * | ||
316 | * which currently is used. * | ||
317 | * * | ||
318 | *****************************************************************************/ | ||
319 | |||
320 | /* called by zft_compress_write() to perform the compression. Must | ||
321 | * return the size of the compressed data. | ||
322 | * | ||
323 | * NOTE: The size of the compressed data should not exceed the size of | ||
324 | * the uncompressed data. Most compression algorithms have means | ||
325 | * to store data unchanged if the "compressed" data amount would | ||
326 | * exceed the original one. Mostly this is done by storing some | ||
327 | * flag-bytes in front of the compressed data to indicate if it | ||
328 | * is compressed or not. Thus the worst compression result | ||
329 | * length is the original length plus those flag-bytes. | ||
330 | * | ||
331 | * We don't want that, as the QIC-80 standard provides a means | ||
332 | * of marking uncompressed blocks by simply setting bit 15 of | ||
333 | * the compressed block's length. Thus a compessed block can | ||
334 | * have at most a length of 2^15-1 bytes. The QIC-80 standard | ||
335 | * restricts the block-length even further, allowing only 29k - | ||
336 | * 6 bytes. | ||
337 | * | ||
338 | * Currently, the maximum blocksize used by zftape is 28k. | ||
339 | * | ||
340 | * In short: don't exceed the length of the input-package, set | ||
341 | * bit 15 of the compressed size to 1 if you have copied data | ||
342 | * instead of compressing it. | ||
343 | */ | ||
344 | static int zft_compress(__u8 *in_buffer, unsigned int in_sz, __u8 *out_buffer) | ||
345 | { | ||
346 | __s32 compressed_sz; | ||
347 | TRACE_FUN(ft_t_flow); | ||
348 | |||
349 | |||
350 | lzrw3_compress(COMPRESS_ACTION_COMPRESS, zftc_wrk_mem, | ||
351 | in_buffer, in_sz, out_buffer, &compressed_sz); | ||
352 | if (TRACE_LEVEL >= ft_t_info) { | ||
353 | /* the compiler will optimize this away when | ||
354 | * compiled with NO_TRACE_AT_ALL option | ||
355 | */ | ||
356 | TRACE(ft_t_data_flow, "\n" | ||
357 | KERN_INFO "before compression: %d bytes\n" | ||
358 | KERN_INFO "after compresison : %d bytes", | ||
359 | in_sz, | ||
360 | (int)(compressed_sz < 0 | ||
361 | ? -compressed_sz : compressed_sz)); | ||
362 | /* for statistical purposes | ||
363 | */ | ||
364 | zftc_wr_compressed += (compressed_sz < 0 | ||
365 | ? -compressed_sz : compressed_sz); | ||
366 | zftc_wr_uncompressed += in_sz; | ||
367 | } | ||
368 | TRACE_EXIT (int)compressed_sz; | ||
369 | } | ||
370 | |||
371 | /* called by zft_compress_read() to decompress the data. Must | ||
372 | * return the size of the decompressed data for sanity checks | ||
373 | * (compared with zft_blk_sz) | ||
374 | * | ||
375 | * NOTE: Read the note for zft_compress() above! If bit 15 of the | ||
376 | * parameter in_sz is set, then the data in in_buffer isn't | ||
377 | * compressed, which must be handled by the un-compression | ||
378 | * algorithm. (I changed lzrw3 to handle this.) | ||
379 | * | ||
380 | * The parameter max_out_sz is needed to prevent buffer overruns when | ||
381 | * uncompressing corrupt data. | ||
382 | */ | ||
383 | static unsigned int zft_uncompress(__u8 *in_buffer, | ||
384 | int in_sz, | ||
385 | __u8 *out_buffer, | ||
386 | unsigned int max_out_sz) | ||
387 | { | ||
388 | TRACE_FUN(ft_t_flow); | ||
389 | |||
390 | lzrw3_compress(COMPRESS_ACTION_DECOMPRESS, zftc_wrk_mem, | ||
391 | in_buffer, (__s32)in_sz, | ||
392 | out_buffer, (__u32 *)&max_out_sz); | ||
393 | |||
394 | if (TRACE_LEVEL >= ft_t_info) { | ||
395 | TRACE(ft_t_data_flow, "\n" | ||
396 | KERN_INFO "before decompression: %d bytes\n" | ||
397 | KERN_INFO "after decompression : %d bytes", | ||
398 | in_sz < 0 ? -in_sz : in_sz,(int)max_out_sz); | ||
399 | /* for statistical purposes | ||
400 | */ | ||
401 | zftc_rd_compressed += in_sz < 0 ? -in_sz : in_sz; | ||
402 | zftc_rd_uncompressed += max_out_sz; | ||
403 | } | ||
404 | TRACE_EXIT (unsigned int)max_out_sz; | ||
405 | } | ||
406 | |||
407 | /* print some statistics about the efficiency of the compression to | ||
408 | * the kernel log | ||
409 | */ | ||
410 | static void zftc_stats(void) | ||
411 | { | ||
412 | TRACE_FUN(ft_t_flow); | ||
413 | |||
414 | if (TRACE_LEVEL < ft_t_info) { | ||
415 | TRACE_EXIT; | ||
416 | } | ||
417 | if (zftc_wr_uncompressed != 0) { | ||
418 | if (zftc_wr_compressed > (1<<14)) { | ||
419 | TRACE(ft_t_info, "compression statistics (writing):\n" | ||
420 | KERN_INFO " compr./uncmpr. : %3d %%", | ||
421 | (((zftc_wr_compressed>>10) * 100) | ||
422 | / (zftc_wr_uncompressed>>10))); | ||
423 | } else { | ||
424 | TRACE(ft_t_info, "compression statistics (writing):\n" | ||
425 | KERN_INFO " compr./uncmpr. : %3d %%", | ||
426 | ((zftc_wr_compressed * 100) | ||
427 | / zftc_wr_uncompressed)); | ||
428 | } | ||
429 | } | ||
430 | if (zftc_rd_uncompressed != 0) { | ||
431 | if (zftc_rd_compressed > (1<<14)) { | ||
432 | TRACE(ft_t_info, "compression statistics (reading):\n" | ||
433 | KERN_INFO " compr./uncmpr. : %3d %%", | ||
434 | (((zftc_rd_compressed>>10) * 100) | ||
435 | / (zftc_rd_uncompressed>>10))); | ||
436 | } else { | ||
437 | TRACE(ft_t_info, "compression statistics (reading):\n" | ||
438 | KERN_INFO " compr./uncmpr. : %3d %%", | ||
439 | ((zftc_rd_compressed * 100) | ||
440 | / zftc_rd_uncompressed)); | ||
441 | } | ||
442 | } | ||
443 | /* only print it once: */ | ||
444 | zftc_wr_uncompressed = | ||
445 | zftc_wr_compressed = | ||
446 | zftc_rd_uncompressed = | ||
447 | zftc_rd_compressed = 0; | ||
448 | TRACE_EXIT; | ||
449 | } | ||
450 | |||
451 | /* start new compressed block | ||
452 | */ | ||
453 | static int start_new_cseg(cmpr_info *cluster, | ||
454 | char *dst_buf, | ||
455 | const zft_position *pos, | ||
456 | const unsigned int blk_sz, | ||
457 | const char *src_buf, | ||
458 | const int this_segs_sz, | ||
459 | const int qic113) | ||
460 | { | ||
461 | int size_left; | ||
462 | int cp_cnt; | ||
463 | int buf_pos; | ||
464 | TRACE_FUN(ft_t_flow); | ||
465 | |||
466 | size_left = this_segs_sz - sizeof(__u16) - cluster->cmpr_sz; | ||
467 | TRACE(ft_t_data_flow,"\n" | ||
468 | KERN_INFO "segment size : %d\n" | ||
469 | KERN_INFO "compressed_sz: %d\n" | ||
470 | KERN_INFO "size_left : %d", | ||
471 | this_segs_sz, cluster->cmpr_sz, size_left); | ||
472 | if (size_left > 18) { /* start a new cluseter */ | ||
473 | cp_cnt = cluster->cmpr_sz; | ||
474 | cluster->cmpr_sz = 0; | ||
475 | buf_pos = cp_cnt + sizeof(__u16); | ||
476 | PUT2(dst_buf, 0, buf_pos); | ||
477 | |||
478 | if (qic113) { | ||
479 | __s64 foffs = pos->volume_pos; | ||
480 | if (cp_cnt) foffs += (__s64)blk_sz; | ||
481 | |||
482 | TRACE(ft_t_data_flow, "new style QIC-113 header"); | ||
483 | PUT8(dst_buf, buf_pos, foffs); | ||
484 | buf_pos += sizeof(__s64); | ||
485 | } else { | ||
486 | __u32 foffs = (__u32)pos->volume_pos; | ||
487 | if (cp_cnt) foffs += (__u32)blk_sz; | ||
488 | |||
489 | TRACE(ft_t_data_flow, "old style QIC-80MC header"); | ||
490 | PUT4(dst_buf, buf_pos, foffs); | ||
491 | buf_pos += sizeof(__u32); | ||
492 | } | ||
493 | } else if (size_left >= 0) { | ||
494 | cp_cnt = cluster->cmpr_sz; | ||
495 | cluster->cmpr_sz = 0; | ||
496 | buf_pos = cp_cnt + sizeof(__u16); | ||
497 | PUT2(dst_buf, 0, buf_pos); | ||
498 | /* zero unused part of segment. */ | ||
499 | memset(dst_buf + buf_pos, '\0', size_left); | ||
500 | buf_pos = this_segs_sz; | ||
501 | } else { /* need entire segment and more space */ | ||
502 | PUT2(dst_buf, 0, 0); | ||
503 | cp_cnt = this_segs_sz - sizeof(__u16); | ||
504 | cluster->cmpr_sz -= cp_cnt; | ||
505 | buf_pos = this_segs_sz; | ||
506 | } | ||
507 | memcpy(dst_buf + sizeof(__u16), src_buf + cluster->cmpr_pos, cp_cnt); | ||
508 | cluster->cmpr_pos += cp_cnt; | ||
509 | TRACE_EXIT buf_pos; | ||
510 | } | ||
511 | |||
512 | /* return-value: the number of bytes removed from the user-buffer | ||
513 | * `src_buf' or error code | ||
514 | * | ||
515 | * int *write_cnt : how much actually has been moved to the | ||
516 | * dst_buf. Need not be initialized when | ||
517 | * function returns with an error code | ||
518 | * (negativ return value) | ||
519 | * __u8 *dst_buf : kernel space buffer where the has to be | ||
520 | * copied to. The contents of this buffers | ||
521 | * goes to a specific segment. | ||
522 | * const int seg_sz : the size of the segment dst_buf will be | ||
523 | * copied to. | ||
524 | * const zft_position *pos : struct containing the coordinates in | ||
525 | * the current volume (byte position, | ||
526 | * segment id of current segment etc) | ||
527 | * const zft_volinfo *volume: information about the current volume, | ||
528 | * size etc. | ||
529 | * const __u8 *src_buf : user space buffer that contains the | ||
530 | * data the user wants to be written to | ||
531 | * tape. | ||
532 | * const int req_len : the amount of data the user wants to be | ||
533 | * written to tape. | ||
534 | */ | ||
535 | static int zftc_write(int *write_cnt, | ||
536 | __u8 *dst_buf, const int seg_sz, | ||
537 | const __u8 __user *src_buf, const int req_len, | ||
538 | const zft_position *pos, const zft_volinfo *volume) | ||
539 | { | ||
540 | int req_len_left = req_len; | ||
541 | int result; | ||
542 | int len_left; | ||
543 | int buf_pos_write = pos->seg_byte_pos; | ||
544 | TRACE_FUN(ft_t_flow); | ||
545 | |||
546 | /* Note: we do not unlock the module because | ||
547 | * there are some values cached in that `cseg' variable. We | ||
548 | * don't don't want to use this information when being | ||
549 | * unloaded by kerneld even when the tape is full or when we | ||
550 | * cannot allocate enough memory. | ||
551 | */ | ||
552 | if (pos->tape_pos > (volume->size-volume->blk_sz-ZFT_CMPR_OVERHEAD)) { | ||
553 | TRACE_EXIT -ENOSPC; | ||
554 | } | ||
555 | if (zft_allocate_cmpr_mem(volume->blk_sz) < 0) { | ||
556 | /* should we unlock the module? But it shouldn't | ||
557 | * be locked anyway ... | ||
558 | */ | ||
559 | TRACE_EXIT -ENOMEM; | ||
560 | } | ||
561 | if (buf_pos_write == 0) { /* fill a new segment */ | ||
562 | *write_cnt = buf_pos_write = start_new_cseg(&cseg, | ||
563 | dst_buf, | ||
564 | pos, | ||
565 | volume->blk_sz, | ||
566 | zftc_buf, | ||
567 | seg_sz, | ||
568 | volume->qic113); | ||
569 | if (cseg.cmpr_sz == 0 && cseg.cmpr_pos != 0) { | ||
570 | req_len_left -= result = volume->blk_sz; | ||
571 | cseg.cmpr_pos = 0; | ||
572 | } else { | ||
573 | result = 0; | ||
574 | } | ||
575 | } else { | ||
576 | *write_cnt = result = 0; | ||
577 | } | ||
578 | |||
579 | len_left = seg_sz - buf_pos_write; | ||
580 | while ((req_len_left > 0) && (len_left > 18)) { | ||
581 | /* now we have some size left for a new compressed | ||
582 | * block. We know, that the compression buffer is | ||
583 | * empty (else there wouldn't be any space left). | ||
584 | */ | ||
585 | if (copy_from_user(zftc_scratch_buf, src_buf + result, | ||
586 | volume->blk_sz) != 0) { | ||
587 | TRACE_EXIT -EFAULT; | ||
588 | } | ||
589 | req_len_left -= volume->blk_sz; | ||
590 | cseg.cmpr_sz = zft_compress(zftc_scratch_buf, volume->blk_sz, | ||
591 | zftc_buf); | ||
592 | if (cseg.cmpr_sz < 0) { | ||
593 | cseg.uncmpr = 0x8000; | ||
594 | cseg.cmpr_sz = -cseg.cmpr_sz; | ||
595 | } else { | ||
596 | cseg.uncmpr = 0; | ||
597 | } | ||
598 | /* increment "result" iff we copied the entire | ||
599 | * compressed block to the zft_deblock_buf | ||
600 | */ | ||
601 | len_left -= sizeof(__u16); | ||
602 | if (len_left >= cseg.cmpr_sz) { | ||
603 | len_left -= cseg.count = cseg.cmpr_sz; | ||
604 | cseg.cmpr_pos = cseg.cmpr_sz = 0; | ||
605 | result += volume->blk_sz; | ||
606 | } else { | ||
607 | cseg.cmpr_sz -= | ||
608 | cseg.cmpr_pos = | ||
609 | cseg.count = len_left; | ||
610 | len_left = 0; | ||
611 | } | ||
612 | PUT2(dst_buf, buf_pos_write, cseg.uncmpr | cseg.count); | ||
613 | buf_pos_write += sizeof(__u16); | ||
614 | memcpy(dst_buf + buf_pos_write, zftc_buf, cseg.count); | ||
615 | buf_pos_write += cseg.count; | ||
616 | *write_cnt += cseg.count + sizeof(__u16); | ||
617 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
618 | } | ||
619 | /* erase the remainder of the segment if less than 18 bytes | ||
620 | * left (18 bytes is due to the QIC-80 standard) | ||
621 | */ | ||
622 | if (len_left <= 18) { | ||
623 | memset(dst_buf + buf_pos_write, '\0', len_left); | ||
624 | (*write_cnt) += len_left; | ||
625 | } | ||
626 | TRACE(ft_t_data_flow, "returning %d", result); | ||
627 | TRACE_EXIT result; | ||
628 | } | ||
629 | |||
630 | /* out: | ||
631 | * | ||
632 | * int *read_cnt: the number of bytes we removed from the zft_deblock_buf | ||
633 | * (result) | ||
634 | * int *to_do : the remaining size of the read-request. | ||
635 | * | ||
636 | * in: | ||
637 | * | ||
638 | * char *buff : buff is the address of the upper part of the user | ||
639 | * buffer, that hasn't been filled with data yet. | ||
640 | |||
641 | * int buf_pos_read : copy of from _ftape_read() | ||
642 | * int buf_len_read : copy of buf_len_rd from _ftape_read() | ||
643 | * char *zft_deblock_buf: zft_deblock_buf | ||
644 | * unsigned short blk_sz: the block size valid for this volume, may differ | ||
645 | * from zft_blk_sz. | ||
646 | * int finish: if != 0 means that this is the last segment belonging | ||
647 | * to this volume | ||
648 | * returns the amount of data actually copied to the user-buffer | ||
649 | * | ||
650 | * to_do MUST NOT SHRINK except to indicate an EOF. In this case *to_do has to | ||
651 | * be set to 0 | ||
652 | */ | ||
653 | static int zftc_read (int *read_cnt, | ||
654 | __u8 __user *dst_buf, const int to_do, | ||
655 | const __u8 *src_buf, const int seg_sz, | ||
656 | const zft_position *pos, const zft_volinfo *volume) | ||
657 | { | ||
658 | int uncompressed_sz; | ||
659 | int result = 0; | ||
660 | int remaining = to_do; | ||
661 | TRACE_FUN(ft_t_flow); | ||
662 | |||
663 | TRACE_CATCH(zft_allocate_cmpr_mem(volume->blk_sz),); | ||
664 | if (pos->seg_byte_pos == 0) { | ||
665 | /* new segment just read | ||
666 | */ | ||
667 | TRACE_CATCH(get_cseg(&cseg, src_buf, seg_sz, volume), | ||
668 | *read_cnt = 0); | ||
669 | memcpy(zftc_buf + cseg.cmpr_pos, src_buf + sizeof(__u16), | ||
670 | cseg.count); | ||
671 | cseg.cmpr_pos += cseg.count; | ||
672 | *read_cnt = cseg.offset; | ||
673 | DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", &cseg); | ||
674 | } else { | ||
675 | *read_cnt = 0; | ||
676 | } | ||
677 | /* loop and uncompress until user buffer full or | ||
678 | * deblock-buffer empty | ||
679 | */ | ||
680 | TRACE(ft_t_data_flow, "compressed_sz: %d, compos : %d, *read_cnt: %d", | ||
681 | cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); | ||
682 | while ((cseg.spans == 0) && (remaining > 0)) { | ||
683 | if (cseg.cmpr_pos != 0) { /* cmpr buf is not empty */ | ||
684 | uncompressed_sz = | ||
685 | zft_uncompress(zftc_buf, | ||
686 | cseg.uncmpr == 0x8000 ? | ||
687 | -cseg.cmpr_pos : cseg.cmpr_pos, | ||
688 | zftc_scratch_buf, | ||
689 | volume->blk_sz); | ||
690 | if (uncompressed_sz != volume->blk_sz) { | ||
691 | *read_cnt = 0; | ||
692 | TRACE_ABORT(-EIO, ft_t_warn, | ||
693 | "Uncompressed blk (%d) != blk size (%d)", | ||
694 | uncompressed_sz, volume->blk_sz); | ||
695 | } | ||
696 | if (copy_to_user(dst_buf + result, | ||
697 | zftc_scratch_buf, | ||
698 | uncompressed_sz) != 0 ) { | ||
699 | TRACE_EXIT -EFAULT; | ||
700 | } | ||
701 | remaining -= uncompressed_sz; | ||
702 | result += uncompressed_sz; | ||
703 | cseg.cmpr_pos = 0; | ||
704 | } | ||
705 | if (remaining > 0) { | ||
706 | get_next_cluster(&cseg, src_buf, seg_sz, | ||
707 | volume->end_seg == pos->seg_pos); | ||
708 | if (cseg.count != 0) { | ||
709 | memcpy(zftc_buf, src_buf + cseg.offset, | ||
710 | cseg.count); | ||
711 | cseg.cmpr_pos = cseg.count; | ||
712 | cseg.offset += cseg.count; | ||
713 | *read_cnt += cseg.count + sizeof(__u16); | ||
714 | } else { | ||
715 | remaining = 0; | ||
716 | } | ||
717 | } | ||
718 | TRACE(ft_t_data_flow, "\n" | ||
719 | KERN_INFO "compressed_sz: %d\n" | ||
720 | KERN_INFO "compos : %d\n" | ||
721 | KERN_INFO "*read_cnt : %d", | ||
722 | cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); | ||
723 | } | ||
724 | if (seg_sz - cseg.offset <= 18) { | ||
725 | *read_cnt += seg_sz - cseg.offset; | ||
726 | TRACE(ft_t_data_flow, "expanding read cnt to: %d", *read_cnt); | ||
727 | } | ||
728 | TRACE(ft_t_data_flow, "\n" | ||
729 | KERN_INFO "segment size : %d\n" | ||
730 | KERN_INFO "read count : %d\n" | ||
731 | KERN_INFO "buf_pos_read : %d\n" | ||
732 | KERN_INFO "remaining : %d", | ||
733 | seg_sz, *read_cnt, pos->seg_byte_pos, | ||
734 | seg_sz - *read_cnt - pos->seg_byte_pos); | ||
735 | TRACE(ft_t_data_flow, "returning: %d", result); | ||
736 | TRACE_EXIT result; | ||
737 | } | ||
738 | |||
739 | /* seeks to the new data-position. Reads sometimes a segment. | ||
740 | * | ||
741 | * start_seg and end_seg give the boundaries of the current volume | ||
742 | * blk_sz is the blk_sz of the current volume as stored in the | ||
743 | * volume label | ||
744 | * | ||
745 | * We don't allow blocksizes less than 1024 bytes, therefore we don't need | ||
746 | * a 64 bit argument for new_block_pos. | ||
747 | */ | ||
748 | |||
749 | static int seek_in_segment(const unsigned int to_do, cmpr_info *c_info, | ||
750 | const char *src_buf, const int seg_sz, | ||
751 | const int seg_pos, const zft_volinfo *volume); | ||
752 | static int slow_seek_forward_until_error(const unsigned int distance, | ||
753 | cmpr_info *c_info, zft_position *pos, | ||
754 | const zft_volinfo *volume, __u8 *buf); | ||
755 | static int search_valid_segment(unsigned int segment, | ||
756 | const unsigned int end_seg, | ||
757 | const unsigned int max_foffs, | ||
758 | zft_position *pos, cmpr_info *c_info, | ||
759 | const zft_volinfo *volume, __u8 *buf); | ||
760 | static int slow_seek_forward(unsigned int dest, cmpr_info *c_info, | ||
761 | zft_position *pos, const zft_volinfo *volume, | ||
762 | __u8 *buf); | ||
763 | static int compute_seg_pos(unsigned int dest, zft_position *pos, | ||
764 | const zft_volinfo *volume); | ||
765 | |||
766 | #define ZFT_SLOW_SEEK_THRESHOLD 10 /* segments */ | ||
767 | #define ZFT_FAST_SEEK_MAX_TRIALS 10 /* times */ | ||
768 | #define ZFT_FAST_SEEK_BACKUP 10 /* segments */ | ||
769 | |||
770 | static int zftc_seek(unsigned int new_block_pos, | ||
771 | zft_position *pos, const zft_volinfo *volume, __u8 *buf) | ||
772 | { | ||
773 | unsigned int dest; | ||
774 | int limit; | ||
775 | int distance; | ||
776 | int result = 0; | ||
777 | int seg_dist; | ||
778 | int new_seg; | ||
779 | int old_seg = 0; | ||
780 | int fast_seek_trials = 0; | ||
781 | TRACE_FUN(ft_t_flow); | ||
782 | |||
783 | if (new_block_pos == 0) { | ||
784 | pos->seg_pos = volume->start_seg; | ||
785 | pos->seg_byte_pos = 0; | ||
786 | pos->volume_pos = 0; | ||
787 | zftc_reset(); | ||
788 | TRACE_EXIT 0; | ||
789 | } | ||
790 | dest = new_block_pos * (volume->blk_sz >> 10); | ||
791 | distance = dest - (pos->volume_pos >> 10); | ||
792 | while (distance != 0) { | ||
793 | seg_dist = compute_seg_pos(dest, pos, volume); | ||
794 | TRACE(ft_t_noise, "\n" | ||
795 | KERN_INFO "seg_dist: %d\n" | ||
796 | KERN_INFO "distance: %d\n" | ||
797 | KERN_INFO "dest : %d\n" | ||
798 | KERN_INFO "vpos : %d\n" | ||
799 | KERN_INFO "seg_pos : %d\n" | ||
800 | KERN_INFO "trials : %d", | ||
801 | seg_dist, distance, dest, | ||
802 | (unsigned int)(pos->volume_pos>>10), pos->seg_pos, | ||
803 | fast_seek_trials); | ||
804 | if (distance > 0) { | ||
805 | if (seg_dist < 0) { | ||
806 | TRACE(ft_t_bug, "BUG: distance %d > 0, " | ||
807 | "segment difference %d < 0", | ||
808 | distance, seg_dist); | ||
809 | result = -EIO; | ||
810 | break; | ||
811 | } | ||
812 | new_seg = pos->seg_pos + seg_dist; | ||
813 | if (new_seg > volume->end_seg) { | ||
814 | new_seg = volume->end_seg; | ||
815 | } | ||
816 | if (old_seg == new_seg || /* loop */ | ||
817 | seg_dist <= ZFT_SLOW_SEEK_THRESHOLD || | ||
818 | fast_seek_trials >= ZFT_FAST_SEEK_MAX_TRIALS) { | ||
819 | TRACE(ft_t_noise, "starting slow seek:\n" | ||
820 | KERN_INFO "fast seek failed too often: %s\n" | ||
821 | KERN_INFO "near target position : %s\n" | ||
822 | KERN_INFO "looping between two segs : %s", | ||
823 | (fast_seek_trials >= | ||
824 | ZFT_FAST_SEEK_MAX_TRIALS) | ||
825 | ? "yes" : "no", | ||
826 | (seg_dist <= ZFT_SLOW_SEEK_THRESHOLD) | ||
827 | ? "yes" : "no", | ||
828 | (old_seg == new_seg) | ||
829 | ? "yes" : "no"); | ||
830 | result = slow_seek_forward(dest, &cseg, | ||
831 | pos, volume, buf); | ||
832 | break; | ||
833 | } | ||
834 | old_seg = new_seg; | ||
835 | limit = volume->end_seg; | ||
836 | fast_seek_trials ++; | ||
837 | for (;;) { | ||
838 | result = search_valid_segment(new_seg, limit, | ||
839 | volume->size, | ||
840 | pos, &cseg, | ||
841 | volume, buf); | ||
842 | if (result == 0 || result == -EINTR) { | ||
843 | break; | ||
844 | } | ||
845 | if (new_seg == volume->start_seg) { | ||
846 | result = -EIO; /* set errror | ||
847 | * condition | ||
848 | */ | ||
849 | break; | ||
850 | } | ||
851 | limit = new_seg; | ||
852 | new_seg -= ZFT_FAST_SEEK_BACKUP; | ||
853 | if (new_seg < volume->start_seg) { | ||
854 | new_seg = volume->start_seg; | ||
855 | } | ||
856 | } | ||
857 | if (result < 0) { | ||
858 | TRACE(ft_t_warn, | ||
859 | "Couldn't find a readable segment"); | ||
860 | break; | ||
861 | } | ||
862 | } else /* if (distance < 0) */ { | ||
863 | if (seg_dist > 0) { | ||
864 | TRACE(ft_t_bug, "BUG: distance %d < 0, " | ||
865 | "segment difference %d >0", | ||
866 | distance, seg_dist); | ||
867 | result = -EIO; | ||
868 | break; | ||
869 | } | ||
870 | new_seg = pos->seg_pos + seg_dist; | ||
871 | if (fast_seek_trials > 0 && seg_dist == 0) { | ||
872 | /* this avoids sticking to the same | ||
873 | * segment all the time. On the other hand: | ||
874 | * if we got here for the first time, and the | ||
875 | * deblock_buffer still contains a valid | ||
876 | * segment, then there is no need to skip to | ||
877 | * the previous segment if the desired position | ||
878 | * is inside this segment. | ||
879 | */ | ||
880 | new_seg --; | ||
881 | } | ||
882 | if (new_seg < volume->start_seg) { | ||
883 | new_seg = volume->start_seg; | ||
884 | } | ||
885 | limit = pos->seg_pos; | ||
886 | fast_seek_trials ++; | ||
887 | for (;;) { | ||
888 | result = search_valid_segment(new_seg, limit, | ||
889 | pos->volume_pos, | ||
890 | pos, &cseg, | ||
891 | volume, buf); | ||
892 | if (result == 0 || result == -EINTR) { | ||
893 | break; | ||
894 | } | ||
895 | if (new_seg == volume->start_seg) { | ||
896 | result = -EIO; /* set errror | ||
897 | * condition | ||
898 | */ | ||
899 | break; | ||
900 | } | ||
901 | limit = new_seg; | ||
902 | new_seg -= ZFT_FAST_SEEK_BACKUP; | ||
903 | if (new_seg < volume->start_seg) { | ||
904 | new_seg = volume->start_seg; | ||
905 | } | ||
906 | } | ||
907 | if (result < 0) { | ||
908 | TRACE(ft_t_warn, | ||
909 | "Couldn't find a readable segment"); | ||
910 | break; | ||
911 | } | ||
912 | } | ||
913 | distance = dest - (pos->volume_pos >> 10); | ||
914 | } | ||
915 | TRACE_EXIT result; | ||
916 | } | ||
917 | |||
918 | |||
919 | /* advance inside the given segment at most to_do bytes. | ||
920 | * of kilobytes moved | ||
921 | */ | ||
922 | |||
923 | static int seek_in_segment(const unsigned int to_do, | ||
924 | cmpr_info *c_info, | ||
925 | const char *src_buf, | ||
926 | const int seg_sz, | ||
927 | const int seg_pos, | ||
928 | const zft_volinfo *volume) | ||
929 | { | ||
930 | int result = 0; | ||
931 | int blk_sz = volume->blk_sz >> 10; | ||
932 | int remaining = to_do; | ||
933 | TRACE_FUN(ft_t_flow); | ||
934 | |||
935 | if (c_info->offset == 0) { | ||
936 | /* new segment just read | ||
937 | */ | ||
938 | TRACE_CATCH(get_cseg(c_info, src_buf, seg_sz, volume),); | ||
939 | c_info->cmpr_pos += c_info->count; | ||
940 | DUMP_CMPR_INFO(ft_t_noise, "", c_info); | ||
941 | } | ||
942 | /* loop and uncompress until user buffer full or | ||
943 | * deblock-buffer empty | ||
944 | */ | ||
945 | TRACE(ft_t_noise, "compressed_sz: %d, compos : %d", | ||
946 | c_info->cmpr_sz, c_info->cmpr_pos); | ||
947 | while (c_info->spans == 0 && remaining > 0) { | ||
948 | if (c_info->cmpr_pos != 0) { /* cmpr buf is not empty */ | ||
949 | result += blk_sz; | ||
950 | remaining -= blk_sz; | ||
951 | c_info->cmpr_pos = 0; | ||
952 | } | ||
953 | if (remaining > 0) { | ||
954 | get_next_cluster(c_info, src_buf, seg_sz, | ||
955 | volume->end_seg == seg_pos); | ||
956 | if (c_info->count != 0) { | ||
957 | c_info->cmpr_pos = c_info->count; | ||
958 | c_info->offset += c_info->count; | ||
959 | } else { | ||
960 | break; | ||
961 | } | ||
962 | } | ||
963 | /* Allow escape from this loop on signal! | ||
964 | */ | ||
965 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
966 | DUMP_CMPR_INFO(ft_t_noise, "", c_info); | ||
967 | TRACE(ft_t_noise, "to_do: %d", remaining); | ||
968 | } | ||
969 | if (seg_sz - c_info->offset <= 18) { | ||
970 | c_info->offset = seg_sz; | ||
971 | } | ||
972 | TRACE(ft_t_noise, "\n" | ||
973 | KERN_INFO "segment size : %d\n" | ||
974 | KERN_INFO "buf_pos_read : %d\n" | ||
975 | KERN_INFO "remaining : %d", | ||
976 | seg_sz, c_info->offset, | ||
977 | seg_sz - c_info->offset); | ||
978 | TRACE_EXIT result; | ||
979 | } | ||
980 | |||
981 | static int slow_seek_forward_until_error(const unsigned int distance, | ||
982 | cmpr_info *c_info, | ||
983 | zft_position *pos, | ||
984 | const zft_volinfo *volume, | ||
985 | __u8 *buf) | ||
986 | { | ||
987 | unsigned int remaining = distance; | ||
988 | int seg_sz; | ||
989 | int seg_pos; | ||
990 | int result; | ||
991 | TRACE_FUN(ft_t_flow); | ||
992 | |||
993 | seg_pos = pos->seg_pos; | ||
994 | do { | ||
995 | TRACE_CATCH(seg_sz = zft_fetch_segment(seg_pos, buf, | ||
996 | FT_RD_AHEAD),); | ||
997 | /* now we have the contents of the actual segment in | ||
998 | * the deblock buffer | ||
999 | */ | ||
1000 | TRACE_CATCH(result = seek_in_segment(remaining, c_info, buf, | ||
1001 | seg_sz, seg_pos,volume),); | ||
1002 | remaining -= result; | ||
1003 | pos->volume_pos += result<<10; | ||
1004 | pos->seg_pos = seg_pos; | ||
1005 | pos->seg_byte_pos = c_info->offset; | ||
1006 | seg_pos ++; | ||
1007 | if (seg_pos <= volume->end_seg && c_info->offset == seg_sz) { | ||
1008 | pos->seg_pos ++; | ||
1009 | pos->seg_byte_pos = 0; | ||
1010 | c_info->offset = 0; | ||
1011 | } | ||
1012 | /* Allow escape from this loop on signal! | ||
1013 | */ | ||
1014 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
1015 | TRACE(ft_t_noise, "\n" | ||
1016 | KERN_INFO "remaining: %d\n" | ||
1017 | KERN_INFO "seg_pos: %d\n" | ||
1018 | KERN_INFO "end_seg: %d\n" | ||
1019 | KERN_INFO "result: %d", | ||
1020 | remaining, seg_pos, volume->end_seg, result); | ||
1021 | } while (remaining > 0 && seg_pos <= volume->end_seg); | ||
1022 | TRACE_EXIT 0; | ||
1023 | } | ||
1024 | |||
1025 | /* return segment id of next segment containing valid data, -EIO otherwise | ||
1026 | */ | ||
1027 | static int search_valid_segment(unsigned int segment, | ||
1028 | const unsigned int end_seg, | ||
1029 | const unsigned int max_foffs, | ||
1030 | zft_position *pos, | ||
1031 | cmpr_info *c_info, | ||
1032 | const zft_volinfo *volume, | ||
1033 | __u8 *buf) | ||
1034 | { | ||
1035 | cmpr_info tmp_info; | ||
1036 | int seg_sz; | ||
1037 | TRACE_FUN(ft_t_flow); | ||
1038 | |||
1039 | memset(&tmp_info, 0, sizeof(cmpr_info)); | ||
1040 | while (segment <= end_seg) { | ||
1041 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
1042 | TRACE(ft_t_noise, | ||
1043 | "Searching readable segment between %d and %d", | ||
1044 | segment, end_seg); | ||
1045 | seg_sz = zft_fetch_segment(segment, buf, FT_RD_AHEAD); | ||
1046 | if ((seg_sz > 0) && | ||
1047 | (get_cseg (&tmp_info, buf, seg_sz, volume) >= 0) && | ||
1048 | (tmp_info.foffs != 0 || segment == volume->start_seg)) { | ||
1049 | if ((tmp_info.foffs>>10) > max_foffs) { | ||
1050 | TRACE_ABORT(-EIO, ft_t_noise, "\n" | ||
1051 | KERN_INFO "cseg.foff: %d\n" | ||
1052 | KERN_INFO "dest : %d", | ||
1053 | (int)(tmp_info.foffs >> 10), | ||
1054 | max_foffs); | ||
1055 | } | ||
1056 | DUMP_CMPR_INFO(ft_t_noise, "", &tmp_info); | ||
1057 | *c_info = tmp_info; | ||
1058 | pos->seg_pos = segment; | ||
1059 | pos->volume_pos = c_info->foffs; | ||
1060 | pos->seg_byte_pos = c_info->offset; | ||
1061 | TRACE(ft_t_noise, "found segment at %d", segment); | ||
1062 | TRACE_EXIT 0; | ||
1063 | } | ||
1064 | segment++; | ||
1065 | } | ||
1066 | TRACE_EXIT -EIO; | ||
1067 | } | ||
1068 | |||
1069 | static int slow_seek_forward(unsigned int dest, | ||
1070 | cmpr_info *c_info, | ||
1071 | zft_position *pos, | ||
1072 | const zft_volinfo *volume, | ||
1073 | __u8 *buf) | ||
1074 | { | ||
1075 | unsigned int distance; | ||
1076 | int result = 0; | ||
1077 | TRACE_FUN(ft_t_flow); | ||
1078 | |||
1079 | distance = dest - (pos->volume_pos >> 10); | ||
1080 | while ((distance > 0) && | ||
1081 | (result = slow_seek_forward_until_error(distance, | ||
1082 | c_info, | ||
1083 | pos, | ||
1084 | volume, | ||
1085 | buf)) < 0) { | ||
1086 | if (result == -EINTR) { | ||
1087 | break; | ||
1088 | } | ||
1089 | TRACE(ft_t_noise, "seg_pos: %d", pos->seg_pos); | ||
1090 | /* the failing segment is either pos->seg_pos or | ||
1091 | * pos->seg_pos + 1. There is no need to further try | ||
1092 | * that segment, because ftape_read_segment() already | ||
1093 | * has tried very much to read it. So we start with | ||
1094 | * following segment, which is pos->seg_pos + 1 | ||
1095 | */ | ||
1096 | if(search_valid_segment(pos->seg_pos+1, volume->end_seg, dest, | ||
1097 | pos, c_info, | ||
1098 | volume, buf) < 0) { | ||
1099 | TRACE(ft_t_noise, "search_valid_segment() failed"); | ||
1100 | result = -EIO; | ||
1101 | break; | ||
1102 | } | ||
1103 | distance = dest - (pos->volume_pos >> 10); | ||
1104 | result = 0; | ||
1105 | TRACE(ft_t_noise, "segment: %d", pos->seg_pos); | ||
1106 | /* found valid segment, retry the seek */ | ||
1107 | } | ||
1108 | TRACE_EXIT result; | ||
1109 | } | ||
1110 | |||
1111 | static int compute_seg_pos(const unsigned int dest, | ||
1112 | zft_position *pos, | ||
1113 | const zft_volinfo *volume) | ||
1114 | { | ||
1115 | int segment; | ||
1116 | int distance = dest - (pos->volume_pos >> 10); | ||
1117 | unsigned int raw_size; | ||
1118 | unsigned int virt_size; | ||
1119 | unsigned int factor; | ||
1120 | TRACE_FUN(ft_t_flow); | ||
1121 | |||
1122 | if (distance >= 0) { | ||
1123 | raw_size = volume->end_seg - pos->seg_pos + 1; | ||
1124 | virt_size = ((unsigned int)(volume->size>>10) | ||
1125 | - (unsigned int)(pos->volume_pos>>10) | ||
1126 | + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1); | ||
1127 | virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS; | ||
1128 | if (virt_size == 0 || raw_size == 0) { | ||
1129 | TRACE_EXIT 0; | ||
1130 | } | ||
1131 | if (raw_size >= (1<<25)) { | ||
1132 | factor = raw_size/(virt_size>>7); | ||
1133 | } else { | ||
1134 | factor = (raw_size<<7)/virt_size; | ||
1135 | } | ||
1136 | segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS); | ||
1137 | segment = (segment * factor)>>7; | ||
1138 | } else { | ||
1139 | raw_size = pos->seg_pos - volume->start_seg + 1; | ||
1140 | virt_size = ((unsigned int)(pos->volume_pos>>10) | ||
1141 | + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1); | ||
1142 | virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS; | ||
1143 | if (virt_size == 0 || raw_size == 0) { | ||
1144 | TRACE_EXIT 0; | ||
1145 | } | ||
1146 | if (raw_size >= (1<<25)) { | ||
1147 | factor = raw_size/(virt_size>>7); | ||
1148 | } else { | ||
1149 | factor = (raw_size<<7)/virt_size; | ||
1150 | } | ||
1151 | segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS); | ||
1152 | } | ||
1153 | TRACE(ft_t_noise, "factor: %d/%d", factor, 1<<7); | ||
1154 | TRACE_EXIT segment; | ||
1155 | } | ||
1156 | |||
1157 | static struct zft_cmpr_ops cmpr_ops = { | ||
1158 | zftc_write, | ||
1159 | zftc_read, | ||
1160 | zftc_seek, | ||
1161 | zftc_lock, | ||
1162 | zftc_reset, | ||
1163 | zftc_cleanup | ||
1164 | }; | ||
1165 | |||
1166 | int zft_compressor_init(void) | ||
1167 | { | ||
1168 | TRACE_FUN(ft_t_flow); | ||
1169 | |||
1170 | #ifdef MODULE | ||
1171 | printk(KERN_INFO "zftape compressor v1.00a 970514 for " FTAPE_VERSION "\n"); | ||
1172 | if (TRACE_LEVEL >= ft_t_info) { | ||
1173 | printk( | ||
1174 | KERN_INFO "(c) 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" | ||
1175 | KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n"); | ||
1176 | } | ||
1177 | #else /* !MODULE */ | ||
1178 | /* print a short no-nonsense boot message */ | ||
1179 | printk(KERN_INFO "zftape compressor v1.00a 970514\n"); | ||
1180 | printk(KERN_INFO "For use with " FTAPE_VERSION "\n"); | ||
1181 | #endif /* MODULE */ | ||
1182 | TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init); | ||
1183 | TRACE(ft_t_info, "installing compressor for zftape ..."); | ||
1184 | TRACE_CATCH(zft_cmpr_register(&cmpr_ops),); | ||
1185 | TRACE_EXIT 0; | ||
1186 | } | ||
1187 | |||
1188 | #ifdef MODULE | ||
1189 | |||
1190 | MODULE_AUTHOR( | ||
1191 | "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de"); | ||
1192 | MODULE_DESCRIPTION( | ||
1193 | "Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams"); | ||
1194 | MODULE_LICENSE("GPL"); | ||
1195 | |||
1196 | /* Called by modules package when installing the driver | ||
1197 | */ | ||
1198 | int init_module(void) | ||
1199 | { | ||
1200 | return zft_compressor_init(); | ||
1201 | } | ||
1202 | |||
1203 | #endif /* MODULE */ | ||
diff --git a/drivers/char/ftape/compressor/zftape-compress.h b/drivers/char/ftape/compressor/zftape-compress.h deleted file mode 100644 index f200741e33bf..000000000000 --- a/drivers/char/ftape/compressor/zftape-compress.h +++ /dev/null | |||
@@ -1,83 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_COMPRESS_H | ||
2 | #define _ZFTAPE_COMPRESS_H | ||
3 | /* | ||
4 | * Copyright (c) 1994-1997 Claus-Justus Heine | ||
5 | |||
6 | This program is free software; you can redistribute it and/or | ||
7 | modify it under the terms of the GNU General Public License as | ||
8 | published by the Free Software Foundation; either version 2, or (at | ||
9 | your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, but | ||
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | 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, | ||
19 | USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/compressor/zftape-compress.h,v $ | ||
23 | * $Revision: 1.1 $ | ||
24 | * $Date: 1997/10/05 19:12:32 $ | ||
25 | * | ||
26 | * This file contains macros and definitions for zftape's | ||
27 | * builtin compression code. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include "../zftape/zftape-buffers.h" | ||
32 | #include "../zftape/zftape-vtbl.h" | ||
33 | #include "../compressor/lzrw3.h" | ||
34 | |||
35 | /* CMPR_WRK_MEM_SIZE gives the size of the compression wrk_mem */ | ||
36 | /* I got these out of lzrw3.c */ | ||
37 | #define U(X) ((__u32) X) | ||
38 | #define SIZE_P_BYTE (U(sizeof(__u8 *))) | ||
39 | #define ALIGNMENT_FUDGE (U(16)) | ||
40 | |||
41 | #define CMPR_WRK_MEM_SIZE (U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE) | ||
42 | |||
43 | /* the maximum number of bytes the size of the "compressed" data can | ||
44 | * exceed the uncompressed data. As it is quite useless to compress | ||
45 | * data twice it is sometimes the case that it is more efficient to | ||
46 | * copy a block of data but to feed it to the "compression" | ||
47 | * algorithm. In this case there are some flag bytes or the like | ||
48 | * proceding the "compressed" data. THAT MUST NOT BE THE CASE for the | ||
49 | * algorithm we use for this driver. Instead, the high bit 15 of | ||
50 | * compressed_size: | ||
51 | * | ||
52 | * compressed_size = ftape_compress() | ||
53 | * | ||
54 | * must be set in such a case. | ||
55 | * | ||
56 | * Nevertheless, it might also be as for lzrw3 that there is an | ||
57 | * "intermediate" overrun that exceeds the amount of the compressed | ||
58 | * data that is actually produced. During the algorithm we need in the | ||
59 | * worst case MAX_CMP_GROUP bytes more than the input-size. | ||
60 | */ | ||
61 | #define MAX_CMP_GROUP (2+16*2) /* from lzrw3.c */ | ||
62 | |||
63 | #define CMPR_OVERRUN MAX_CMP_GROUP /* during compression */ | ||
64 | |||
65 | /****************************************************/ | ||
66 | |||
67 | #define CMPR_BUFFER_SIZE (MAX_BLOCK_SIZE + CMPR_OVERRUN) | ||
68 | |||
69 | /* the compression map stores the byte offset compressed blocks within | ||
70 | * the current volume for catridges with format code 2,3 and 5 | ||
71 | * (and old versions of zftape) and the offset measured in kilobytes for | ||
72 | * format code 4 and 6. This gives us a possible max. size of a | ||
73 | * compressed volume of 1024*4GIG which should be enough. | ||
74 | */ | ||
75 | typedef __u32 CmprMap; | ||
76 | |||
77 | /* globals | ||
78 | */ | ||
79 | |||
80 | /* exported functions | ||
81 | */ | ||
82 | |||
83 | #endif /* _ZFTAPE_COMPRESS_H */ | ||
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 | |||
diff --git a/drivers/char/ftape/zftape/Makefile b/drivers/char/ftape/zftape/Makefile deleted file mode 100644 index 6d91c1f77c05..000000000000 --- a/drivers/char/ftape/zftape/Makefile +++ /dev/null | |||
@@ -1,36 +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 | # $Source: /homes/cvs/ftape-stacked/ftape/zftape/Makefile,v $ | ||
19 | # $Revision: 1.4 $ | ||
20 | # $Date: 1997/10/05 19:18:58 $ | ||
21 | # | ||
22 | # Makefile for the QIC-40/80/3010/3020 zftape interface VFS to | ||
23 | # ftape | ||
24 | # | ||
25 | |||
26 | |||
27 | # ZFT_OBSOLETE - enable the MTIOC_ZFTAPE_GETBLKSZ ioctl. You should | ||
28 | # leave this enabled for compatibility with taper. | ||
29 | |||
30 | obj-$(CONFIG_ZFTAPE) += zftape.o | ||
31 | |||
32 | zftape-objs := zftape-rw.o zftape-ctl.o zftape-read.o \ | ||
33 | zftape-write.o zftape-vtbl.o zftape-eof.o \ | ||
34 | zftape-init.o zftape-buffers.o zftape_syms.o | ||
35 | |||
36 | EXTRA_CFLAGS := -DZFT_OBSOLETE | ||
diff --git a/drivers/char/ftape/zftape/zftape-buffers.c b/drivers/char/ftape/zftape/zftape-buffers.c deleted file mode 100644 index 7ebce2ec7897..000000000000 --- a/drivers/char/ftape/zftape/zftape-buffers.c +++ /dev/null | |||
@@ -1,149 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1995-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/zftape/zftape-buffers.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:18:59 $ | ||
22 | * | ||
23 | * This file contains the dynamic buffer allocation routines | ||
24 | * of zftape | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/delay.h> | ||
31 | |||
32 | #include <linux/zftape.h> | ||
33 | |||
34 | #include <linux/vmalloc.h> | ||
35 | |||
36 | #include "../zftape/zftape-init.h" | ||
37 | #include "../zftape/zftape-eof.h" | ||
38 | #include "../zftape/zftape-ctl.h" | ||
39 | #include "../zftape/zftape-write.h" | ||
40 | #include "../zftape/zftape-read.h" | ||
41 | #include "../zftape/zftape-rw.h" | ||
42 | #include "../zftape/zftape-vtbl.h" | ||
43 | |||
44 | /* global variables | ||
45 | */ | ||
46 | |||
47 | /* local varibales | ||
48 | */ | ||
49 | static unsigned int used_memory; | ||
50 | static unsigned int peak_memory; | ||
51 | |||
52 | void zft_memory_stats(void) | ||
53 | { | ||
54 | TRACE_FUN(ft_t_flow); | ||
55 | |||
56 | TRACE(ft_t_noise, "Memory usage (vmalloc allocations):\n" | ||
57 | KERN_INFO "total allocated: %d\n" | ||
58 | KERN_INFO "peak allocation: %d", | ||
59 | used_memory, peak_memory); | ||
60 | peak_memory = used_memory; | ||
61 | TRACE_EXIT; | ||
62 | } | ||
63 | |||
64 | int zft_vcalloc_once(void *new, size_t size) | ||
65 | { | ||
66 | TRACE_FUN(ft_t_flow); | ||
67 | if (zft_vmalloc_once(new, size) < 0) { | ||
68 | TRACE_EXIT -ENOMEM; | ||
69 | } | ||
70 | memset(*(void **)new, '\0', size); | ||
71 | TRACE_EXIT 0; | ||
72 | } | ||
73 | int zft_vmalloc_once(void *new, size_t size) | ||
74 | { | ||
75 | TRACE_FUN(ft_t_flow); | ||
76 | |||
77 | if (*(void **)new != NULL || size == 0) { | ||
78 | TRACE_EXIT 0; | ||
79 | } | ||
80 | if ((*(void **)new = vmalloc(size)) == NULL) { | ||
81 | TRACE_EXIT -ENOMEM; | ||
82 | } | ||
83 | used_memory += size; | ||
84 | if (peak_memory < used_memory) { | ||
85 | peak_memory = used_memory; | ||
86 | } | ||
87 | TRACE_ABORT(0, ft_t_noise, | ||
88 | "allocated buffer @ %p, %zd bytes", *(void **)new, size); | ||
89 | } | ||
90 | int zft_vmalloc_always(void *new, size_t size) | ||
91 | { | ||
92 | TRACE_FUN(ft_t_flow); | ||
93 | |||
94 | zft_vfree(new, size); | ||
95 | TRACE_EXIT zft_vmalloc_once(new, size); | ||
96 | } | ||
97 | void zft_vfree(void *old, size_t size) | ||
98 | { | ||
99 | TRACE_FUN(ft_t_flow); | ||
100 | |||
101 | if (*(void **)old) { | ||
102 | vfree(*(void **)old); | ||
103 | used_memory -= size; | ||
104 | TRACE(ft_t_noise, "released buffer @ %p, %zd bytes", | ||
105 | *(void **)old, size); | ||
106 | *(void **)old = NULL; | ||
107 | } | ||
108 | TRACE_EXIT; | ||
109 | } | ||
110 | |||
111 | void *zft_kmalloc(size_t size) | ||
112 | { | ||
113 | void *new; | ||
114 | |||
115 | while ((new = kmalloc(size, GFP_KERNEL)) == NULL) { | ||
116 | msleep_interruptible(100); | ||
117 | } | ||
118 | memset(new, 0, size); | ||
119 | used_memory += size; | ||
120 | if (peak_memory < used_memory) { | ||
121 | peak_memory = used_memory; | ||
122 | } | ||
123 | return new; | ||
124 | } | ||
125 | |||
126 | void zft_kfree(void *old, size_t size) | ||
127 | { | ||
128 | kfree(old); | ||
129 | used_memory -= size; | ||
130 | } | ||
131 | |||
132 | /* there are some more buffers that are allocated on demand. | ||
133 | * cleanup_module() calles this function to be sure to have released | ||
134 | * them | ||
135 | */ | ||
136 | void zft_uninit_mem(void) | ||
137 | { | ||
138 | TRACE_FUN(ft_t_flow); | ||
139 | |||
140 | zft_vfree(&zft_hseg_buf, FT_SEGMENT_SIZE); | ||
141 | zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); zft_deblock_segment = -1; | ||
142 | zft_free_vtbl(); | ||
143 | if (zft_cmpr_lock(0 /* don't load */) == 0) { | ||
144 | (*zft_cmpr_ops->cleanup)(); | ||
145 | (*zft_cmpr_ops->reset)(); /* unlock it again */ | ||
146 | } | ||
147 | zft_memory_stats(); | ||
148 | TRACE_EXIT; | ||
149 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-buffers.h b/drivers/char/ftape/zftape/zftape-buffers.h deleted file mode 100644 index 798e3128c682..000000000000 --- a/drivers/char/ftape/zftape/zftape-buffers.h +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | #ifndef _FTAPE_DYNMEM_H | ||
2 | #define _FTAPE_DYNMEM_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1995-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/zftape/zftape-buffers.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:18:59 $ | ||
25 | * | ||
26 | * memory allocation routines. | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | /* we do not allocate all of the really large buffer memory before | ||
31 | * someone tries to open the drive. ftape_open() may fail with | ||
32 | * -ENOMEM, but that's better having 200k of vmalloced memory which | ||
33 | * cannot be swapped out. | ||
34 | */ | ||
35 | |||
36 | extern void zft_memory_stats(void); | ||
37 | extern int zft_vmalloc_once(void *new, size_t size); | ||
38 | extern int zft_vcalloc_once(void *new, size_t size); | ||
39 | extern int zft_vmalloc_always(void *new, size_t size); | ||
40 | extern void zft_vfree(void *old, size_t size); | ||
41 | extern void *zft_kmalloc(size_t size); | ||
42 | extern void zft_kfree(void *old, size_t size); | ||
43 | |||
44 | /* called by cleanup_module() | ||
45 | */ | ||
46 | extern void zft_uninit_mem(void); | ||
47 | |||
48 | #endif | ||
49 | |||
50 | |||
51 | |||
52 | |||
53 | |||
54 | |||
55 | |||
diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c deleted file mode 100644 index 22ba0f5d00cf..000000000000 --- a/drivers/char/ftape/zftape/zftape-ctl.c +++ /dev/null | |||
@@ -1,1417 +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/zftape/zftape-ctl.c,v $ | ||
20 | * $Revision: 1.2.6.2 $ | ||
21 | * $Date: 1997/11/14 18:07:33 $ | ||
22 | * | ||
23 | * This file contains the non-read/write zftape functions | ||
24 | * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/fcntl.h> | ||
31 | |||
32 | #include <linux/zftape.h> | ||
33 | |||
34 | #include <asm/uaccess.h> | ||
35 | |||
36 | #include "../zftape/zftape-init.h" | ||
37 | #include "../zftape/zftape-eof.h" | ||
38 | #include "../zftape/zftape-ctl.h" | ||
39 | #include "../zftape/zftape-write.h" | ||
40 | #include "../zftape/zftape-read.h" | ||
41 | #include "../zftape/zftape-rw.h" | ||
42 | #include "../zftape/zftape-vtbl.h" | ||
43 | |||
44 | /* Global vars. | ||
45 | */ | ||
46 | int zft_write_protected; /* this is when cartridge rdonly or O_RDONLY */ | ||
47 | int zft_header_read; | ||
48 | int zft_offline; | ||
49 | unsigned int zft_unit; | ||
50 | int zft_resid; | ||
51 | int zft_mt_compression; | ||
52 | |||
53 | /* Local vars. | ||
54 | */ | ||
55 | static int going_offline; | ||
56 | |||
57 | typedef int (mt_fun)(int *argptr); | ||
58 | typedef int (*mt_funp)(int *argptr); | ||
59 | typedef struct | ||
60 | { | ||
61 | mt_funp function; | ||
62 | unsigned offline : 1; /* op permitted if offline or no_tape */ | ||
63 | unsigned write_protected : 1; /* op permitted if write-protected */ | ||
64 | unsigned not_formatted : 1; /* op permitted if tape not formatted */ | ||
65 | unsigned raw_mode : 1; /* op permitted if zft_mode == 0 */ | ||
66 | unsigned need_idle_state : 1; /* need to call def_idle_state */ | ||
67 | char *name; | ||
68 | } fun_entry; | ||
69 | |||
70 | static mt_fun mt_dummy, mt_reset, mt_fsr, mt_bsr, mt_rew, mt_offl, mt_nop, | ||
71 | mt_weof, mt_erase, mt_ras2, mt_setblk, mt_setdensity, | ||
72 | mt_seek, mt_tell, mt_reten, mt_eom, mt_fsf, mt_bsf, | ||
73 | mt_fsfm, mt_bsfm, mt_setdrvbuffer, mt_compression; | ||
74 | |||
75 | static fun_entry mt_funs[]= | ||
76 | { | ||
77 | {mt_reset , 1, 1, 1, 1, 0, "MT_RESET" }, /* 0 */ | ||
78 | {mt_fsf , 0, 1, 0, 0, 1, "MT_FSF" }, | ||
79 | {mt_bsf , 0, 1, 0, 0, 1, "MT_BSF" }, | ||
80 | {mt_fsr , 0, 1, 0, 1, 1, "MT_FSR" }, | ||
81 | {mt_bsr , 0, 1, 0, 1, 1, "MT_BSR" }, | ||
82 | {mt_weof , 0, 0, 0, 0, 0, "MT_WEOF" }, /* 5 */ | ||
83 | {mt_rew , 0, 1, 1, 1, 0, "MT_REW" }, | ||
84 | {mt_offl , 0, 1, 1, 1, 0, "MT_OFFL" }, | ||
85 | {mt_nop , 1, 1, 1, 1, 0, "MT_NOP" }, | ||
86 | {mt_reten , 0, 1, 1, 1, 0, "MT_RETEN" }, | ||
87 | {mt_bsfm , 0, 1, 0, 0, 1, "MT_BSFM" }, /* 10 */ | ||
88 | {mt_fsfm , 0, 1, 0, 0, 1, "MT_FSFM" }, | ||
89 | {mt_eom , 0, 1, 0, 0, 1, "MT_EOM" }, | ||
90 | {mt_erase , 0, 0, 0, 1, 0, "MT_ERASE" }, | ||
91 | {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS1" }, | ||
92 | {mt_ras2 , 0, 0, 0, 1, 0, "MT_RAS2" }, | ||
93 | {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS3" }, | ||
94 | {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, | ||
95 | {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, | ||
96 | {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, | ||
97 | {mt_setblk , 1, 1, 1, 1, 1, "MT_SETBLK"}, /* 20 */ | ||
98 | {mt_setdensity , 1, 1, 1, 1, 0, "MT_SETDENSITY"}, | ||
99 | {mt_seek , 0, 1, 0, 1, 1, "MT_SEEK" }, | ||
100 | {mt_dummy , 0, 1, 0, 1, 1, "MT_TELL" }, /* wr-only ?! */ | ||
101 | {mt_setdrvbuffer, 1, 1, 1, 1, 0, "MT_SETDRVBUFFER" }, | ||
102 | {mt_dummy , 1, 1, 1, 1, 0, "MT_FSS" }, /* 25 */ | ||
103 | {mt_dummy , 1, 1, 1, 1, 0, "MT_BSS" }, | ||
104 | {mt_dummy , 1, 1, 1, 1, 0, "MT_WSM" }, | ||
105 | {mt_dummy , 1, 1, 1, 1, 0, "MT_LOCK" }, | ||
106 | {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOCK"}, | ||
107 | {mt_dummy , 1, 1, 1, 1, 0, "MT_LOAD" }, /* 30 */ | ||
108 | {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOAD"}, | ||
109 | {mt_compression , 1, 1, 1, 0, 1, "MT_COMPRESSION"}, | ||
110 | {mt_dummy , 1, 1, 1, 1, 0, "MT_SETPART"}, | ||
111 | {mt_dummy , 1, 1, 1, 1, 0, "MT_MKPART"} | ||
112 | }; | ||
113 | |||
114 | #define NR_MT_CMDS NR_ITEMS(mt_funs) | ||
115 | |||
116 | void zft_reset_position(zft_position *pos) | ||
117 | { | ||
118 | TRACE_FUN(ft_t_flow); | ||
119 | |||
120 | pos->seg_byte_pos = | ||
121 | pos->volume_pos = 0; | ||
122 | if (zft_header_read) { | ||
123 | /* need to keep track of the volume table and | ||
124 | * compression map. We therefor simply | ||
125 | * position at the beginning of the first | ||
126 | * volume. This covers old ftape archives as | ||
127 | * well has various flavours of the | ||
128 | * compression map segments. The worst case is | ||
129 | * that the compression map shows up as a | ||
130 | * additional volume in front of all others. | ||
131 | */ | ||
132 | pos->seg_pos = zft_find_volume(0)->start_seg; | ||
133 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
134 | } else { | ||
135 | pos->tape_pos = 0; | ||
136 | pos->seg_pos = -1; | ||
137 | } | ||
138 | zft_just_before_eof = 0; | ||
139 | zft_deblock_segment = -1; | ||
140 | zft_io_state = zft_idle; | ||
141 | zft_zap_read_buffers(); | ||
142 | zft_prevent_flush(); | ||
143 | /* unlock the compresison module if it is loaded. | ||
144 | * The zero arg means not to try to load the module. | ||
145 | */ | ||
146 | if (zft_cmpr_lock(0) == 0) { | ||
147 | (*zft_cmpr_ops->reset)(); /* unlock */ | ||
148 | } | ||
149 | TRACE_EXIT; | ||
150 | } | ||
151 | |||
152 | static void zft_init_driver(void) | ||
153 | { | ||
154 | TRACE_FUN(ft_t_flow); | ||
155 | |||
156 | zft_resid = | ||
157 | zft_header_read = | ||
158 | zft_old_ftape = | ||
159 | zft_offline = | ||
160 | zft_write_protected = | ||
161 | going_offline = | ||
162 | zft_mt_compression = | ||
163 | zft_header_changed = | ||
164 | zft_volume_table_changed = | ||
165 | zft_written_segments = 0; | ||
166 | zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; | ||
167 | zft_reset_position(&zft_pos); /* does most of the stuff */ | ||
168 | ftape_zap_read_buffers(); | ||
169 | ftape_set_state(idle); | ||
170 | TRACE_EXIT; | ||
171 | } | ||
172 | |||
173 | int zft_def_idle_state(void) | ||
174 | { | ||
175 | int result = 0; | ||
176 | TRACE_FUN(ft_t_flow); | ||
177 | |||
178 | if (!zft_header_read) { | ||
179 | result = zft_read_header_segments(); | ||
180 | } else if ((result = zft_flush_buffers()) >= 0 && zft_qic_mode) { | ||
181 | /* don't move past eof | ||
182 | */ | ||
183 | (void)zft_close_volume(&zft_pos); | ||
184 | } | ||
185 | if (ftape_abort_operation() < 0) { | ||
186 | TRACE(ft_t_warn, "ftape_abort_operation() failed"); | ||
187 | result = -EIO; | ||
188 | } | ||
189 | /* clear remaining read buffers */ | ||
190 | zft_zap_read_buffers(); | ||
191 | zft_io_state = zft_idle; | ||
192 | TRACE_EXIT result; | ||
193 | } | ||
194 | |||
195 | /***************************************************************************** | ||
196 | * * | ||
197 | * functions for the MTIOCTOP commands * | ||
198 | * * | ||
199 | *****************************************************************************/ | ||
200 | |||
201 | static int mt_dummy(int *dummy) | ||
202 | { | ||
203 | TRACE_FUN(ft_t_flow); | ||
204 | |||
205 | TRACE_EXIT -ENOSYS; | ||
206 | } | ||
207 | |||
208 | static int mt_reset(int *dummy) | ||
209 | { | ||
210 | TRACE_FUN(ft_t_flow); | ||
211 | |||
212 | (void)ftape_seek_to_bot(); | ||
213 | TRACE_CATCH(ftape_reset_drive(), | ||
214 | zft_init_driver(); zft_uninit_mem(); zft_offline = 1); | ||
215 | /* fake a re-open of the device. This will set all flage and | ||
216 | * allocate buffers as appropriate. The new tape condition will | ||
217 | * force the open routine to do anything we need. | ||
218 | */ | ||
219 | TRACE_CATCH(_zft_open(-1 /* fake reopen */, 0 /* dummy */),); | ||
220 | TRACE_EXIT 0; | ||
221 | } | ||
222 | |||
223 | static int mt_fsf(int *arg) | ||
224 | { | ||
225 | int result; | ||
226 | TRACE_FUN(ft_t_flow); | ||
227 | |||
228 | result = zft_skip_volumes(*arg, &zft_pos); | ||
229 | zft_just_before_eof = 0; | ||
230 | TRACE_EXIT result; | ||
231 | } | ||
232 | |||
233 | static int mt_bsf(int *arg) | ||
234 | { | ||
235 | int result = 0; | ||
236 | TRACE_FUN(ft_t_flow); | ||
237 | |||
238 | if (*arg != 0) { | ||
239 | result = zft_skip_volumes(-*arg + 1, &zft_pos); | ||
240 | } | ||
241 | TRACE_EXIT result; | ||
242 | } | ||
243 | |||
244 | static int seek_block(__s64 data_offset, | ||
245 | __s64 block_increment, | ||
246 | zft_position *pos) | ||
247 | { | ||
248 | int result = 0; | ||
249 | __s64 new_block_pos; | ||
250 | __s64 vol_block_count; | ||
251 | const zft_volinfo *volume; | ||
252 | int exceed; | ||
253 | TRACE_FUN(ft_t_flow); | ||
254 | |||
255 | volume = zft_find_volume(pos->seg_pos); | ||
256 | if (volume->start_seg == 0 || volume->end_seg == 0) { | ||
257 | TRACE_EXIT -EIO; | ||
258 | } | ||
259 | new_block_pos = (zft_div_blksz(data_offset, volume->blk_sz) | ||
260 | + block_increment); | ||
261 | vol_block_count = zft_div_blksz(volume->size, volume->blk_sz); | ||
262 | if (new_block_pos < 0) { | ||
263 | TRACE(ft_t_noise, | ||
264 | "new_block_pos " LL_X " < 0", LL(new_block_pos)); | ||
265 | zft_resid = (int)new_block_pos; | ||
266 | new_block_pos = 0; | ||
267 | exceed = 1; | ||
268 | } else if (new_block_pos > vol_block_count) { | ||
269 | TRACE(ft_t_noise, | ||
270 | "new_block_pos " LL_X " exceeds size of volume " LL_X, | ||
271 | LL(new_block_pos), LL(vol_block_count)); | ||
272 | zft_resid = (int)(vol_block_count - new_block_pos); | ||
273 | new_block_pos = vol_block_count; | ||
274 | exceed = 1; | ||
275 | } else { | ||
276 | exceed = 0; | ||
277 | } | ||
278 | if (zft_use_compression && volume->use_compression) { | ||
279 | TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); | ||
280 | result = (*zft_cmpr_ops->seek)(new_block_pos, pos, volume, | ||
281 | zft_deblock_buf); | ||
282 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
283 | pos->tape_pos += pos->seg_byte_pos; | ||
284 | } else { | ||
285 | pos->volume_pos = zft_mul_blksz(new_block_pos, volume->blk_sz); | ||
286 | pos->tape_pos = zft_calc_tape_pos(volume->start_seg); | ||
287 | pos->tape_pos += pos->volume_pos; | ||
288 | pos->seg_pos = zft_calc_seg_byte_coord(&pos->seg_byte_pos, | ||
289 | pos->tape_pos); | ||
290 | } | ||
291 | zft_just_before_eof = volume->size == pos->volume_pos; | ||
292 | if (zft_just_before_eof) { | ||
293 | /* why this? because zft_file_no checks agains start | ||
294 | * and end segment of a volume. We do not want to | ||
295 | * advance to the next volume with this function. | ||
296 | */ | ||
297 | TRACE(ft_t_noise, "set zft_just_before_eof"); | ||
298 | zft_position_before_eof(pos, volume); | ||
299 | } | ||
300 | TRACE(ft_t_noise, "\n" | ||
301 | KERN_INFO "new_seg_pos : %d\n" | ||
302 | KERN_INFO "new_tape_pos: " LL_X "\n" | ||
303 | KERN_INFO "vol_size : " LL_X "\n" | ||
304 | KERN_INFO "seg_byte_pos: %d\n" | ||
305 | KERN_INFO "blk_sz : %d", | ||
306 | pos->seg_pos, LL(pos->tape_pos), | ||
307 | LL(volume->size), pos->seg_byte_pos, | ||
308 | volume->blk_sz); | ||
309 | if (!exceed) { | ||
310 | zft_resid = new_block_pos - zft_div_blksz(pos->volume_pos, | ||
311 | volume->blk_sz); | ||
312 | } | ||
313 | if (zft_resid < 0) { | ||
314 | zft_resid = -zft_resid; | ||
315 | } | ||
316 | TRACE_EXIT ((exceed || zft_resid != 0) && result >= 0) ? -EINVAL : result; | ||
317 | } | ||
318 | |||
319 | static int mt_fsr(int *arg) | ||
320 | { | ||
321 | int result; | ||
322 | TRACE_FUN(ft_t_flow); | ||
323 | |||
324 | result = seek_block(zft_pos.volume_pos, *arg, &zft_pos); | ||
325 | TRACE_EXIT result; | ||
326 | } | ||
327 | |||
328 | static int mt_bsr(int *arg) | ||
329 | { | ||
330 | int result; | ||
331 | TRACE_FUN(ft_t_flow); | ||
332 | |||
333 | result = seek_block(zft_pos.volume_pos, -*arg, &zft_pos); | ||
334 | TRACE_EXIT result; | ||
335 | } | ||
336 | |||
337 | static int mt_weof(int *arg) | ||
338 | { | ||
339 | int result; | ||
340 | TRACE_FUN(ft_t_flow); | ||
341 | |||
342 | TRACE_CATCH(zft_flush_buffers(),); | ||
343 | result = zft_weof(*arg, &zft_pos); | ||
344 | TRACE_EXIT result; | ||
345 | } | ||
346 | |||
347 | static int mt_rew(int *dummy) | ||
348 | { | ||
349 | int result; | ||
350 | TRACE_FUN(ft_t_flow); | ||
351 | |||
352 | if(zft_header_read) { | ||
353 | (void)zft_def_idle_state(); | ||
354 | } | ||
355 | result = ftape_seek_to_bot(); | ||
356 | zft_reset_position(&zft_pos); | ||
357 | TRACE_EXIT result; | ||
358 | } | ||
359 | |||
360 | static int mt_offl(int *dummy) | ||
361 | { | ||
362 | int result; | ||
363 | TRACE_FUN(ft_t_flow); | ||
364 | |||
365 | going_offline= 1; | ||
366 | result = mt_rew(NULL); | ||
367 | TRACE_EXIT result; | ||
368 | } | ||
369 | |||
370 | static int mt_nop(int *dummy) | ||
371 | { | ||
372 | TRACE_FUN(ft_t_flow); | ||
373 | /* should we set tape status? | ||
374 | */ | ||
375 | if (!zft_offline) { /* offline includes no_tape */ | ||
376 | (void)zft_def_idle_state(); | ||
377 | } | ||
378 | TRACE_EXIT 0; | ||
379 | } | ||
380 | |||
381 | static int mt_reten(int *dummy) | ||
382 | { | ||
383 | int result; | ||
384 | TRACE_FUN(ft_t_flow); | ||
385 | |||
386 | if(zft_header_read) { | ||
387 | (void)zft_def_idle_state(); | ||
388 | } | ||
389 | result = ftape_seek_to_eot(); | ||
390 | if (result >= 0) { | ||
391 | result = ftape_seek_to_bot(); | ||
392 | } | ||
393 | TRACE_EXIT(result); | ||
394 | } | ||
395 | |||
396 | static int fsfbsfm(int arg, zft_position *pos) | ||
397 | { | ||
398 | const zft_volinfo *vtbl; | ||
399 | __s64 block_pos; | ||
400 | TRACE_FUN(ft_t_flow); | ||
401 | |||
402 | /* What to do? This should seek to the next file-mark and | ||
403 | * position BEFORE. That is, a next write would just extend | ||
404 | * the current file. Well. Let's just seek to the end of the | ||
405 | * current file, if count == 1. If count > 1, then do a | ||
406 | * "mt_fsf(count - 1)", and then seek to the end of that file. | ||
407 | * If count == 0, do nothing | ||
408 | */ | ||
409 | if (arg == 0) { | ||
410 | TRACE_EXIT 0; | ||
411 | } | ||
412 | zft_just_before_eof = 0; | ||
413 | TRACE_CATCH(zft_skip_volumes(arg < 0 ? arg : arg-1, pos), | ||
414 | if (arg > 0) { | ||
415 | zft_resid ++; | ||
416 | }); | ||
417 | vtbl = zft_find_volume(pos->seg_pos); | ||
418 | block_pos = zft_div_blksz(vtbl->size, vtbl->blk_sz); | ||
419 | (void)seek_block(0, block_pos, pos); | ||
420 | if (pos->volume_pos != vtbl->size) { | ||
421 | zft_just_before_eof = 0; | ||
422 | zft_resid = 1; | ||
423 | /* we didn't managed to go there */ | ||
424 | TRACE_ABORT(-EIO, ft_t_err, | ||
425 | "wanted file position " LL_X ", arrived at " LL_X, | ||
426 | LL(vtbl->size), LL(pos->volume_pos)); | ||
427 | } | ||
428 | zft_just_before_eof = 1; | ||
429 | TRACE_EXIT 0; | ||
430 | } | ||
431 | |||
432 | static int mt_bsfm(int *arg) | ||
433 | { | ||
434 | int result; | ||
435 | TRACE_FUN(ft_t_flow); | ||
436 | |||
437 | result = fsfbsfm(-*arg, &zft_pos); | ||
438 | TRACE_EXIT result; | ||
439 | } | ||
440 | |||
441 | static int mt_fsfm(int *arg) | ||
442 | { | ||
443 | int result; | ||
444 | TRACE_FUN(ft_t_flow); | ||
445 | |||
446 | result = fsfbsfm(*arg, &zft_pos); | ||
447 | TRACE_EXIT result; | ||
448 | } | ||
449 | |||
450 | static int mt_eom(int *dummy) | ||
451 | { | ||
452 | TRACE_FUN(ft_t_flow); | ||
453 | |||
454 | zft_skip_to_eom(&zft_pos); | ||
455 | TRACE_EXIT 0; | ||
456 | } | ||
457 | |||
458 | static int mt_erase(int *dummy) | ||
459 | { | ||
460 | int result; | ||
461 | TRACE_FUN(ft_t_flow); | ||
462 | |||
463 | result = zft_erase(); | ||
464 | TRACE_EXIT result; | ||
465 | } | ||
466 | |||
467 | static int mt_ras2(int *dummy) | ||
468 | { | ||
469 | int result; | ||
470 | TRACE_FUN(ft_t_flow); | ||
471 | |||
472 | result = -ENOSYS; | ||
473 | TRACE_EXIT result; | ||
474 | } | ||
475 | |||
476 | /* Sets the new blocksize in BYTES | ||
477 | * | ||
478 | */ | ||
479 | static int mt_setblk(int *new_size) | ||
480 | { | ||
481 | TRACE_FUN(ft_t_flow); | ||
482 | |||
483 | if((unsigned int)(*new_size) > ZFT_MAX_BLK_SZ) { | ||
484 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
485 | "desired blk_sz (%d) should be <= %d bytes", | ||
486 | *new_size, ZFT_MAX_BLK_SZ); | ||
487 | } | ||
488 | if ((*new_size & (FT_SECTOR_SIZE-1)) != 0) { | ||
489 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
490 | "desired blk_sz (%d) must be a multiple of %d bytes", | ||
491 | *new_size, FT_SECTOR_SIZE); | ||
492 | } | ||
493 | if (*new_size == 0) { | ||
494 | if (zft_use_compression) { | ||
495 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
496 | "Variable block size not yet " | ||
497 | "supported with compression"); | ||
498 | } | ||
499 | *new_size = 1; | ||
500 | } | ||
501 | zft_blk_sz = *new_size; | ||
502 | TRACE_EXIT 0; | ||
503 | } | ||
504 | |||
505 | static int mt_setdensity(int *arg) | ||
506 | { | ||
507 | TRACE_FUN(ft_t_flow); | ||
508 | |||
509 | SET_TRACE_LEVEL(*arg); | ||
510 | TRACE(TRACE_LEVEL, "tracing set to %d", TRACE_LEVEL); | ||
511 | if ((int)TRACE_LEVEL != *arg) { | ||
512 | TRACE_EXIT -EINVAL; | ||
513 | } | ||
514 | TRACE_EXIT 0; | ||
515 | } | ||
516 | |||
517 | static int mt_seek(int *new_block_pos) | ||
518 | { | ||
519 | int result= 0; | ||
520 | TRACE_FUN(ft_t_any); | ||
521 | |||
522 | result = seek_block(0, (__s64)*new_block_pos, &zft_pos); | ||
523 | TRACE_EXIT result; | ||
524 | } | ||
525 | |||
526 | /* OK, this is totally different from SCSI, but the worst thing that can | ||
527 | * happen is that there is not enough defragmentated memory that can be | ||
528 | * allocated. Also, there is a hardwired limit of 16 dma buffers in the | ||
529 | * stock ftape module. This shouldn't bring the system down. | ||
530 | * | ||
531 | * NOTE: the argument specifies the total number of dma buffers to use. | ||
532 | * The driver needs at least 3 buffers to function at all. | ||
533 | * | ||
534 | */ | ||
535 | static int mt_setdrvbuffer(int *cnt) | ||
536 | { | ||
537 | TRACE_FUN(ft_t_flow); | ||
538 | |||
539 | if (*cnt < 3) { | ||
540 | TRACE_EXIT -EINVAL; | ||
541 | } | ||
542 | TRACE_CATCH(ftape_set_nr_buffers(*cnt),); | ||
543 | TRACE_EXIT 0; | ||
544 | } | ||
545 | /* return the block position from start of volume | ||
546 | */ | ||
547 | static int mt_tell(int *arg) | ||
548 | { | ||
549 | TRACE_FUN(ft_t_flow); | ||
550 | |||
551 | *arg = zft_div_blksz(zft_pos.volume_pos, | ||
552 | zft_find_volume(zft_pos.seg_pos)->blk_sz); | ||
553 | TRACE_EXIT 0; | ||
554 | } | ||
555 | |||
556 | static int mt_compression(int *arg) | ||
557 | { | ||
558 | TRACE_FUN(ft_t_flow); | ||
559 | |||
560 | /* Ok. We could also check whether compression is available at | ||
561 | * all by trying to load the compression module. We could | ||
562 | * also check for a block size of 1 byte which is illegal | ||
563 | * with compression. Instead of doing it here we rely on | ||
564 | * zftape_write() to do the proper checks. | ||
565 | */ | ||
566 | if ((unsigned int)*arg > 1) { | ||
567 | TRACE_EXIT -EINVAL; | ||
568 | } | ||
569 | if (*arg != 0 && zft_blk_sz == 1) { /* variable block size */ | ||
570 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
571 | "Compression not yet supported " | ||
572 | "with variable block size"); | ||
573 | } | ||
574 | zft_mt_compression = *arg; | ||
575 | if ((zft_unit & ZFT_ZIP_MODE) == 0) { | ||
576 | zft_use_compression = zft_mt_compression; | ||
577 | } | ||
578 | TRACE_EXIT 0; | ||
579 | } | ||
580 | |||
581 | /* check whether write access is allowed. Write access is denied when | ||
582 | * + zft_write_protected == 1 -- this accounts for either hard write | ||
583 | * protection of the cartridge or for | ||
584 | * O_RDONLY access mode of the tape device | ||
585 | * + zft_offline == 1 -- this meany that there is either no tape | ||
586 | * or that the MTOFFLINE ioctl has been | ||
587 | * previously issued (`soft eject') | ||
588 | * + ft_formatted == 0 -- this means that the cartridge is not | ||
589 | * formatted | ||
590 | * Then we distinuguish two cases. When zft_qic_mode is TRUE, then we try | ||
591 | * to emulate a `traditional' (aka SCSI like) UN*X tape device. Therefore we | ||
592 | * deny writes when | ||
593 | * + zft_qic_mode ==1 && | ||
594 | * (!zft_tape_at_lbot() && -- tape no at logical BOT | ||
595 | * !(zft_tape_at_eom() || -- tape not at logical EOM (or EOD) | ||
596 | * (zft_tape_at_eom() && | ||
597 | * zft_old_ftape()))) -- we can't add new volume to tapes | ||
598 | * written by old ftape because ftape | ||
599 | * don't use the volume table | ||
600 | * | ||
601 | * when the drive is in true raw mode (aka /dev/rawft0) then we don't | ||
602 | * care about LBOT and EOM conditions. This device is intended for a | ||
603 | * user level program that wants to truly implement the QIC-80 compliance | ||
604 | * at the logical data layout level of the cartridge, i.e. implement all | ||
605 | * that volume table and volume directory stuff etc.< | ||
606 | */ | ||
607 | int zft_check_write_access(zft_position *pos) | ||
608 | { | ||
609 | TRACE_FUN(ft_t_flow); | ||
610 | |||
611 | if (zft_offline) { /* offline includes no_tape */ | ||
612 | TRACE_ABORT(-ENXIO, | ||
613 | ft_t_info, "tape is offline or no cartridge"); | ||
614 | } | ||
615 | if (!ft_formatted) { | ||
616 | TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); | ||
617 | } | ||
618 | if (zft_write_protected) { | ||
619 | TRACE_ABORT(-EACCES, ft_t_info, "cartridge write protected"); | ||
620 | } | ||
621 | if (zft_qic_mode) { | ||
622 | /* check BOT condition */ | ||
623 | if (!zft_tape_at_lbot(pos)) { | ||
624 | /* protect cartridges written by old ftape if | ||
625 | * not at BOT because they use the vtbl | ||
626 | * segment for storing data | ||
627 | */ | ||
628 | if (zft_old_ftape) { | ||
629 | TRACE_ABORT(-EACCES, ft_t_warn, | ||
630 | "Cannot write to cartridges written by old ftape when not at BOT"); | ||
631 | } | ||
632 | /* not at BOT, but allow writes at EOD, of course | ||
633 | */ | ||
634 | if (!zft_tape_at_eod(pos)) { | ||
635 | TRACE_ABORT(-EACCES, ft_t_info, | ||
636 | "tape not at BOT and not at EOD"); | ||
637 | } | ||
638 | } | ||
639 | /* fine. Now the tape is either at BOT or at EOD. */ | ||
640 | } | ||
641 | /* or in raw mode in which case we don't care about BOT and EOD */ | ||
642 | TRACE_EXIT 0; | ||
643 | } | ||
644 | |||
645 | /* OPEN routine called by kernel-interface code | ||
646 | * | ||
647 | * NOTE: this is also called by mt_reset() with dev_minor == -1 | ||
648 | * to fake a reopen after a reset. | ||
649 | */ | ||
650 | int _zft_open(unsigned int dev_minor, unsigned int access_mode) | ||
651 | { | ||
652 | static unsigned int tape_unit; | ||
653 | static unsigned int file_access_mode; | ||
654 | int result; | ||
655 | TRACE_FUN(ft_t_flow); | ||
656 | |||
657 | if ((int)dev_minor == -1) { | ||
658 | /* fake reopen */ | ||
659 | zft_unit = tape_unit; | ||
660 | access_mode = file_access_mode; | ||
661 | zft_init_driver(); /* reset all static data to defaults */ | ||
662 | } else { | ||
663 | tape_unit = dev_minor; | ||
664 | file_access_mode = access_mode; | ||
665 | if ((result = ftape_enable(FTAPE_SEL(dev_minor))) < 0) { | ||
666 | TRACE_ABORT(-ENXIO, ft_t_err, | ||
667 | "ftape_enable failed: %d", result); | ||
668 | } | ||
669 | if (ft_new_tape || ft_no_tape || !ft_formatted || | ||
670 | (FTAPE_SEL(zft_unit) != FTAPE_SEL(dev_minor)) || | ||
671 | (zft_unit & ZFT_RAW_MODE) != (dev_minor & ZFT_RAW_MODE)) { | ||
672 | /* reset all static data to defaults, | ||
673 | */ | ||
674 | zft_init_driver(); | ||
675 | } | ||
676 | zft_unit = dev_minor; | ||
677 | } | ||
678 | zft_set_flags(zft_unit); /* decode the minor bits */ | ||
679 | if (zft_blk_sz == 1 && zft_use_compression) { | ||
680 | ftape_disable(); /* resets ft_no_tape */ | ||
681 | TRACE_ABORT(-ENODEV, ft_t_warn, "Variable block size not yet " | ||
682 | "supported with compression"); | ||
683 | } | ||
684 | /* no need for most of the buffers when no tape or not | ||
685 | * formatted. for the read/write operations, it is the | ||
686 | * regardless whether there is no tape, a not-formatted tape | ||
687 | * or the whether the driver is soft offline. | ||
688 | * Nevertheless we allow some ioctls with non-formatted tapes, | ||
689 | * like rewind and reset. | ||
690 | */ | ||
691 | if (ft_no_tape || !ft_formatted) { | ||
692 | zft_uninit_mem(); | ||
693 | } | ||
694 | if (ft_no_tape) { | ||
695 | zft_offline = 1; /* so we need not test two variables */ | ||
696 | } | ||
697 | if ((access_mode == O_WRONLY || access_mode == O_RDWR) && | ||
698 | (ft_write_protected || ft_no_tape)) { | ||
699 | ftape_disable(); /* resets ft_no_tape */ | ||
700 | TRACE_ABORT(ft_no_tape ? -ENXIO : -EROFS, | ||
701 | ft_t_warn, "wrong access mode %s cartridge", | ||
702 | ft_no_tape ? "without a" : "with write protected"); | ||
703 | } | ||
704 | zft_write_protected = (access_mode == O_RDONLY || | ||
705 | ft_write_protected != 0); | ||
706 | if (zft_write_protected) { | ||
707 | TRACE(ft_t_noise, | ||
708 | "read only access mode: %d, " | ||
709 | "drive write protected: %d", | ||
710 | access_mode == O_RDONLY, | ||
711 | ft_write_protected != 0); | ||
712 | } | ||
713 | if (!zft_offline) { | ||
714 | TRACE_CATCH(zft_vmalloc_once(&zft_deblock_buf,FT_SEGMENT_SIZE), | ||
715 | ftape_disable()); | ||
716 | } | ||
717 | /* zft_seg_pos should be greater than the vtbl segpos but not | ||
718 | * if in compatibility mode and only after we read in the | ||
719 | * header segments | ||
720 | * | ||
721 | * might also be a problem if the user makes a backup with a | ||
722 | * *qft* device and rewinds it with a raw device. | ||
723 | */ | ||
724 | if (zft_qic_mode && | ||
725 | !zft_old_ftape && | ||
726 | zft_pos.seg_pos >= 0 && | ||
727 | zft_header_read && | ||
728 | zft_pos.seg_pos <= ft_first_data_segment) { | ||
729 | TRACE(ft_t_noise, "you probably mixed up the zftape devices!"); | ||
730 | zft_reset_position(&zft_pos); | ||
731 | } | ||
732 | TRACE_EXIT 0; | ||
733 | } | ||
734 | |||
735 | /* RELEASE routine called by kernel-interface code | ||
736 | */ | ||
737 | int _zft_close(void) | ||
738 | { | ||
739 | int result = 0; | ||
740 | TRACE_FUN(ft_t_flow); | ||
741 | |||
742 | if (zft_offline) { | ||
743 | /* call the hardware release routine. Puts the drive offline */ | ||
744 | ftape_disable(); | ||
745 | TRACE_EXIT 0; | ||
746 | } | ||
747 | if (!(ft_write_protected || zft_old_ftape)) { | ||
748 | result = zft_flush_buffers(); | ||
749 | TRACE(ft_t_noise, "writing file mark at current position"); | ||
750 | if (zft_qic_mode && zft_close_volume(&zft_pos) == 0) { | ||
751 | zft_move_past_eof(&zft_pos); | ||
752 | } | ||
753 | if ((zft_tape_at_lbot(&zft_pos) || | ||
754 | !(zft_unit & FTAPE_NO_REWIND))) { | ||
755 | if (result >= 0) { | ||
756 | result = zft_update_header_segments(); | ||
757 | } else { | ||
758 | TRACE(ft_t_err, | ||
759 | "Error: unable to update header segments"); | ||
760 | } | ||
761 | } | ||
762 | } | ||
763 | ftape_abort_operation(); | ||
764 | if (!(zft_unit & FTAPE_NO_REWIND)) { | ||
765 | TRACE(ft_t_noise, "rewinding tape"); | ||
766 | if (ftape_seek_to_bot() < 0 && result >= 0) { | ||
767 | result = -EIO; /* keep old value */ | ||
768 | } | ||
769 | zft_reset_position(&zft_pos); | ||
770 | } | ||
771 | zft_zap_read_buffers(); | ||
772 | /* now free up memory as much as possible. We don't destroy | ||
773 | * the deblock buffer if it containes a valid segment. | ||
774 | */ | ||
775 | if (zft_deblock_segment == -1) { | ||
776 | zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); | ||
777 | } | ||
778 | /* high level driver status, forces creation of a new volume | ||
779 | * when calling ftape_write again and not zft_just_before_eof | ||
780 | */ | ||
781 | zft_io_state = zft_idle; | ||
782 | if (going_offline) { | ||
783 | zft_init_driver(); | ||
784 | zft_uninit_mem(); | ||
785 | going_offline = 0; | ||
786 | zft_offline = 1; | ||
787 | } else if (zft_cmpr_lock(0 /* don't load */) == 0) { | ||
788 | (*zft_cmpr_ops->reset)(); /* unlock it again */ | ||
789 | } | ||
790 | zft_memory_stats(); | ||
791 | /* call the hardware release routine. Puts the drive offline */ | ||
792 | ftape_disable(); | ||
793 | TRACE_EXIT result; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * the wrapper function around the wrapper MTIOCTOP ioctl | ||
798 | */ | ||
799 | static int mtioctop(struct mtop *mtop, int arg_size) | ||
800 | { | ||
801 | int result = 0; | ||
802 | fun_entry *mt_fun_entry; | ||
803 | TRACE_FUN(ft_t_flow); | ||
804 | |||
805 | if (arg_size != sizeof(struct mtop) || mtop->mt_op >= NR_MT_CMDS) { | ||
806 | TRACE_EXIT -EINVAL; | ||
807 | } | ||
808 | TRACE(ft_t_noise, "calling MTIOCTOP command: %s", | ||
809 | mt_funs[mtop->mt_op].name); | ||
810 | mt_fun_entry= &mt_funs[mtop->mt_op]; | ||
811 | zft_resid = mtop->mt_count; | ||
812 | if (!mt_fun_entry->offline && zft_offline) { | ||
813 | if (ft_no_tape) { | ||
814 | TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); | ||
815 | } else { | ||
816 | TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); | ||
817 | } | ||
818 | } | ||
819 | if (!mt_fun_entry->not_formatted && !ft_formatted) { | ||
820 | TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); | ||
821 | } | ||
822 | if (!mt_fun_entry->write_protected) { | ||
823 | TRACE_CATCH(zft_check_write_access(&zft_pos),); | ||
824 | } | ||
825 | if (mt_fun_entry->need_idle_state && !(zft_offline || !ft_formatted)) { | ||
826 | TRACE_CATCH(zft_def_idle_state(),); | ||
827 | } | ||
828 | if (!zft_qic_mode && !mt_fun_entry->raw_mode) { | ||
829 | TRACE_ABORT(-EACCES, ft_t_info, | ||
830 | "Drive needs to be in QIC-80 compatibility mode for this command"); | ||
831 | } | ||
832 | result = (mt_fun_entry->function)(&mtop->mt_count); | ||
833 | if (zft_tape_at_lbot(&zft_pos)) { | ||
834 | TRACE_CATCH(zft_update_header_segments(),); | ||
835 | } | ||
836 | if (result >= 0) { | ||
837 | zft_resid = 0; | ||
838 | } | ||
839 | TRACE_EXIT result; | ||
840 | } | ||
841 | |||
842 | /* | ||
843 | * standard MTIOCGET ioctl | ||
844 | */ | ||
845 | static int mtiocget(struct mtget *mtget, int arg_size) | ||
846 | { | ||
847 | const zft_volinfo *volume; | ||
848 | __s64 max_tape_pos; | ||
849 | TRACE_FUN(ft_t_flow); | ||
850 | |||
851 | if (arg_size != sizeof(struct mtget)) { | ||
852 | TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", | ||
853 | arg_size); | ||
854 | } | ||
855 | mtget->mt_type = ft_drive_type.vendor_id + 0x800000; | ||
856 | mtget->mt_dsreg = ft_last_status.space; | ||
857 | mtget->mt_erreg = ft_last_error.space; /* error register */ | ||
858 | mtget->mt_resid = zft_resid; /* residuum of writes, reads and | ||
859 | * MTIOCTOP commands | ||
860 | */ | ||
861 | if (!zft_offline) { /* neither no_tape nor soft offline */ | ||
862 | mtget->mt_gstat = GMT_ONLINE(~0UL); | ||
863 | /* should rather return the status of the cartridge | ||
864 | * than the access mode of the file, therefor use | ||
865 | * ft_write_protected, not zft_write_protected | ||
866 | */ | ||
867 | if (ft_write_protected) { | ||
868 | mtget->mt_gstat |= GMT_WR_PROT(~0UL); | ||
869 | } | ||
870 | if(zft_header_read) { /* this catches non-formatted */ | ||
871 | volume = zft_find_volume(zft_pos.seg_pos); | ||
872 | mtget->mt_fileno = volume->count; | ||
873 | max_tape_pos = zft_capacity - zft_blk_sz; | ||
874 | if (zft_use_compression) { | ||
875 | max_tape_pos -= ZFT_CMPR_OVERHEAD; | ||
876 | } | ||
877 | if (zft_tape_at_eod(&zft_pos)) { | ||
878 | mtget->mt_gstat |= GMT_EOD(~0UL); | ||
879 | } | ||
880 | if (zft_pos.tape_pos > max_tape_pos) { | ||
881 | mtget->mt_gstat |= GMT_EOT(~0UL); | ||
882 | } | ||
883 | mtget->mt_blkno = zft_div_blksz(zft_pos.volume_pos, | ||
884 | volume->blk_sz); | ||
885 | if (zft_just_before_eof) { | ||
886 | mtget->mt_gstat |= GMT_EOF(~0UL); | ||
887 | } | ||
888 | if (zft_tape_at_lbot(&zft_pos)) { | ||
889 | mtget->mt_gstat |= GMT_BOT(~0UL); | ||
890 | } | ||
891 | } else { | ||
892 | mtget->mt_fileno = mtget->mt_blkno = -1; | ||
893 | if (mtget->mt_dsreg & QIC_STATUS_AT_BOT) { | ||
894 | mtget->mt_gstat |= GMT_BOT(~0UL); | ||
895 | } | ||
896 | } | ||
897 | } else { | ||
898 | if (ft_no_tape) { | ||
899 | mtget->mt_gstat = GMT_DR_OPEN(~0UL); | ||
900 | } else { | ||
901 | mtget->mt_gstat = 0UL; | ||
902 | } | ||
903 | mtget->mt_fileno = mtget->mt_blkno = -1; | ||
904 | } | ||
905 | TRACE_EXIT 0; | ||
906 | } | ||
907 | |||
908 | #ifdef MTIOCRDFTSEG | ||
909 | /* | ||
910 | * Read a floppy tape segment. This is useful for manipulating the | ||
911 | * volume table, and read the old header segment before re-formatting | ||
912 | * the cartridge. | ||
913 | */ | ||
914 | static int mtiocrdftseg(struct mtftseg * mtftseg, int arg_size) | ||
915 | { | ||
916 | TRACE_FUN(ft_t_flow); | ||
917 | |||
918 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCRDFTSEG"); | ||
919 | if (zft_qic_mode) { | ||
920 | TRACE_ABORT(-EACCES, ft_t_info, | ||
921 | "driver needs to be in raw mode for this ioctl"); | ||
922 | } | ||
923 | if (arg_size != sizeof(struct mtftseg)) { | ||
924 | TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", | ||
925 | arg_size); | ||
926 | } | ||
927 | if (zft_offline) { | ||
928 | TRACE_EXIT -ENXIO; | ||
929 | } | ||
930 | if (mtftseg->mt_mode != FT_RD_SINGLE && | ||
931 | mtftseg->mt_mode != FT_RD_AHEAD) { | ||
932 | TRACE_ABORT(-EINVAL, ft_t_info, "invalid read mode"); | ||
933 | } | ||
934 | if (!ft_formatted) { | ||
935 | TRACE_EXIT -EACCES; /* -ENXIO ? */ | ||
936 | |||
937 | } | ||
938 | if (!zft_header_read) { | ||
939 | TRACE_CATCH(zft_def_idle_state(),); | ||
940 | } | ||
941 | if (mtftseg->mt_segno > ft_last_data_segment) { | ||
942 | TRACE_ABORT(-EINVAL, ft_t_info, "segment number is too large"); | ||
943 | } | ||
944 | mtftseg->mt_result = ftape_read_segment(mtftseg->mt_segno, | ||
945 | zft_deblock_buf, | ||
946 | mtftseg->mt_mode); | ||
947 | if (mtftseg->mt_result < 0) { | ||
948 | /* a negativ result is not an ioctl error. if | ||
949 | * the user wants to read damaged tapes, | ||
950 | * it's up to her/him | ||
951 | */ | ||
952 | TRACE_EXIT 0; | ||
953 | } | ||
954 | if (copy_to_user(mtftseg->mt_data, | ||
955 | zft_deblock_buf, | ||
956 | mtftseg->mt_result) != 0) { | ||
957 | TRACE_EXIT -EFAULT; | ||
958 | } | ||
959 | TRACE_EXIT 0; | ||
960 | } | ||
961 | #endif | ||
962 | |||
963 | #ifdef MTIOCWRFTSEG | ||
964 | /* | ||
965 | * write a floppy tape segment. This version features writing of | ||
966 | * deleted address marks, and gracefully ignores the (software) | ||
967 | * ft_formatted flag to support writing of header segments after | ||
968 | * formatting. | ||
969 | */ | ||
970 | static int mtiocwrftseg(struct mtftseg * mtftseg, int arg_size) | ||
971 | { | ||
972 | int result; | ||
973 | TRACE_FUN(ft_t_flow); | ||
974 | |||
975 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCWRFTSEG"); | ||
976 | if (zft_write_protected || zft_qic_mode) { | ||
977 | TRACE_EXIT -EACCES; | ||
978 | } | ||
979 | if (arg_size != sizeof(struct mtftseg)) { | ||
980 | TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", | ||
981 | arg_size); | ||
982 | } | ||
983 | if (zft_offline) { | ||
984 | TRACE_EXIT -ENXIO; | ||
985 | } | ||
986 | if (mtftseg->mt_mode != FT_WR_ASYNC && | ||
987 | mtftseg->mt_mode != FT_WR_MULTI && | ||
988 | mtftseg->mt_mode != FT_WR_SINGLE && | ||
989 | mtftseg->mt_mode != FT_WR_DELETE) { | ||
990 | TRACE_ABORT(-EINVAL, ft_t_info, "invalid write mode"); | ||
991 | } | ||
992 | /* | ||
993 | * We don't check for ft_formatted, because this gives | ||
994 | * only the software status of the driver. | ||
995 | * | ||
996 | * We assume that the user knows what it is | ||
997 | * doing. And rely on the low level stuff to fail | ||
998 | * when the tape isn't formatted. We only make sure | ||
999 | * that The header segment buffer is allocated, | ||
1000 | * because it holds the bad sector map. | ||
1001 | */ | ||
1002 | if (zft_hseg_buf == NULL) { | ||
1003 | TRACE_EXIT -ENXIO; | ||
1004 | } | ||
1005 | if (mtftseg->mt_mode != FT_WR_DELETE) { | ||
1006 | if (copy_from_user(zft_deblock_buf, | ||
1007 | mtftseg->mt_data, | ||
1008 | FT_SEGMENT_SIZE) != 0) { | ||
1009 | TRACE_EXIT -EFAULT; | ||
1010 | } | ||
1011 | } | ||
1012 | mtftseg->mt_result = ftape_write_segment(mtftseg->mt_segno, | ||
1013 | zft_deblock_buf, | ||
1014 | mtftseg->mt_mode); | ||
1015 | if (mtftseg->mt_result >= 0 && mtftseg->mt_mode == FT_WR_SINGLE) { | ||
1016 | /* | ||
1017 | * a negativ result is not an ioctl error. if | ||
1018 | * the user wants to write damaged tapes, | ||
1019 | * it's up to her/him | ||
1020 | */ | ||
1021 | if ((result = ftape_loop_until_writes_done()) < 0) { | ||
1022 | mtftseg->mt_result = result; | ||
1023 | } | ||
1024 | } | ||
1025 | TRACE_EXIT 0; | ||
1026 | } | ||
1027 | #endif | ||
1028 | |||
1029 | #ifdef MTIOCVOLINFO | ||
1030 | /* | ||
1031 | * get information about volume positioned at. | ||
1032 | */ | ||
1033 | static int mtiocvolinfo(struct mtvolinfo *volinfo, int arg_size) | ||
1034 | { | ||
1035 | const zft_volinfo *volume; | ||
1036 | TRACE_FUN(ft_t_flow); | ||
1037 | |||
1038 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCVOLINFO"); | ||
1039 | if (arg_size != sizeof(struct mtvolinfo)) { | ||
1040 | TRACE_ABORT(-EINVAL, | ||
1041 | ft_t_info, "bad argument size: %d", arg_size); | ||
1042 | } | ||
1043 | if (zft_offline) { | ||
1044 | TRACE_EXIT -ENXIO; | ||
1045 | } | ||
1046 | if (!ft_formatted) { | ||
1047 | TRACE_EXIT -EACCES; | ||
1048 | } | ||
1049 | TRACE_CATCH(zft_def_idle_state(),); | ||
1050 | volume = zft_find_volume(zft_pos.seg_pos); | ||
1051 | volinfo->mt_volno = volume->count; | ||
1052 | volinfo->mt_blksz = volume->blk_sz == 1 ? 0 : volume->blk_sz; | ||
1053 | volinfo->mt_size = volume->size >> 10; | ||
1054 | volinfo->mt_rawsize = ((zft_calc_tape_pos(volume->end_seg + 1) >> 10) - | ||
1055 | (zft_calc_tape_pos(volume->start_seg) >> 10)); | ||
1056 | volinfo->mt_cmpr = volume->use_compression; | ||
1057 | TRACE_EXIT 0; | ||
1058 | } | ||
1059 | #endif | ||
1060 | |||
1061 | #ifdef ZFT_OBSOLETE | ||
1062 | static int mtioc_zftape_getblksz(struct mtblksz *blksz, int arg_size) | ||
1063 | { | ||
1064 | TRACE_FUN(ft_t_flow); | ||
1065 | |||
1066 | TRACE(ft_t_noise, "\n" | ||
1067 | KERN_INFO "Mag tape ioctl command: MTIOC_ZTAPE_GETBLKSZ\n" | ||
1068 | KERN_INFO "This ioctl is here merely for compatibility.\n" | ||
1069 | KERN_INFO "Please use MTIOCVOLINFO instead"); | ||
1070 | if (arg_size != sizeof(struct mtblksz)) { | ||
1071 | TRACE_ABORT(-EINVAL, | ||
1072 | ft_t_info, "bad argument size: %d", arg_size); | ||
1073 | } | ||
1074 | if (zft_offline) { | ||
1075 | TRACE_EXIT -ENXIO; | ||
1076 | } | ||
1077 | if (!ft_formatted) { | ||
1078 | TRACE_EXIT -EACCES; | ||
1079 | } | ||
1080 | TRACE_CATCH(zft_def_idle_state(),); | ||
1081 | blksz->mt_blksz = zft_find_volume(zft_pos.seg_pos)->blk_sz; | ||
1082 | TRACE_EXIT 0; | ||
1083 | } | ||
1084 | #endif | ||
1085 | |||
1086 | #ifdef MTIOCGETSIZE | ||
1087 | /* | ||
1088 | * get the capacity of the tape cartridge. | ||
1089 | */ | ||
1090 | static int mtiocgetsize(struct mttapesize *size, int arg_size) | ||
1091 | { | ||
1092 | TRACE_FUN(ft_t_flow); | ||
1093 | |||
1094 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOC_ZFTAPE_GETSIZE"); | ||
1095 | if (arg_size != sizeof(struct mttapesize)) { | ||
1096 | TRACE_ABORT(-EINVAL, | ||
1097 | ft_t_info, "bad argument size: %d", arg_size); | ||
1098 | } | ||
1099 | if (zft_offline) { | ||
1100 | TRACE_EXIT -ENXIO; | ||
1101 | } | ||
1102 | if (!ft_formatted) { | ||
1103 | TRACE_EXIT -EACCES; | ||
1104 | } | ||
1105 | TRACE_CATCH(zft_def_idle_state(),); | ||
1106 | size->mt_capacity = (unsigned int)(zft_capacity>>10); | ||
1107 | size->mt_used = (unsigned int)(zft_get_eom_pos()>>10); | ||
1108 | TRACE_EXIT 0; | ||
1109 | } | ||
1110 | #endif | ||
1111 | |||
1112 | static int mtiocpos(struct mtpos *mtpos, int arg_size) | ||
1113 | { | ||
1114 | int result; | ||
1115 | TRACE_FUN(ft_t_flow); | ||
1116 | |||
1117 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCPOS"); | ||
1118 | if (arg_size != sizeof(struct mtpos)) { | ||
1119 | TRACE_ABORT(-EINVAL, | ||
1120 | ft_t_info, "bad argument size: %d", arg_size); | ||
1121 | } | ||
1122 | result = mt_tell((int *)&mtpos->mt_blkno); | ||
1123 | TRACE_EXIT result; | ||
1124 | } | ||
1125 | |||
1126 | #ifdef MTIOCFTFORMAT | ||
1127 | /* | ||
1128 | * formatting of floppy tape cartridges. This is intended to be used | ||
1129 | * together with the MTIOCFTCMD ioctl and the new mmap feature | ||
1130 | */ | ||
1131 | |||
1132 | /* | ||
1133 | * This function uses ftape_decode_header_segment() to inform the low | ||
1134 | * level ftape module about the new parameters. | ||
1135 | * | ||
1136 | * It erases the hseg_buf. The calling process must specify all | ||
1137 | * parameters to assure proper operation. | ||
1138 | * | ||
1139 | * return values: -EINVAL - wrong argument size | ||
1140 | * -EINVAL - if ftape_decode_header_segment() failed. | ||
1141 | */ | ||
1142 | static int set_format_parms(struct ftfmtparms *p, __u8 *hseg_buf) | ||
1143 | { | ||
1144 | ft_trace_t old_level = TRACE_LEVEL; | ||
1145 | TRACE_FUN(ft_t_flow); | ||
1146 | |||
1147 | TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_SETPARMS"); | ||
1148 | memset(hseg_buf, 0, FT_SEGMENT_SIZE); | ||
1149 | PUT4(hseg_buf, FT_SIGNATURE, FT_HSEG_MAGIC); | ||
1150 | |||
1151 | /* fill in user specified parameters | ||
1152 | */ | ||
1153 | hseg_buf[FT_FMT_CODE] = (__u8)p->ft_fmtcode; | ||
1154 | PUT2(hseg_buf, FT_SPT, p->ft_spt); | ||
1155 | hseg_buf[FT_TPC] = (__u8)p->ft_tpc; | ||
1156 | hseg_buf[FT_FHM] = (__u8)p->ft_fhm; | ||
1157 | hseg_buf[FT_FTM] = (__u8)p->ft_ftm; | ||
1158 | |||
1159 | /* fill in sane defaults to make ftape happy. | ||
1160 | */ | ||
1161 | hseg_buf[FT_FSM] = (__u8)128; /* 128 is hard wired all over ftape */ | ||
1162 | if (p->ft_fmtcode == fmt_big) { | ||
1163 | PUT4(hseg_buf, FT_6_HSEG_1, 0); | ||
1164 | PUT4(hseg_buf, FT_6_HSEG_2, 1); | ||
1165 | PUT4(hseg_buf, FT_6_FRST_SEG, 2); | ||
1166 | PUT4(hseg_buf, FT_6_LAST_SEG, p->ft_spt * p->ft_tpc - 1); | ||
1167 | } else { | ||
1168 | PUT2(hseg_buf, FT_HSEG_1, 0); | ||
1169 | PUT2(hseg_buf, FT_HSEG_2, 1); | ||
1170 | PUT2(hseg_buf, FT_FRST_SEG, 2); | ||
1171 | PUT2(hseg_buf, FT_LAST_SEG, p->ft_spt * p->ft_tpc - 1); | ||
1172 | } | ||
1173 | |||
1174 | /* Synchronize with the low level module. This is particularly | ||
1175 | * needed for unformatted cartridges as the QIC std was previously | ||
1176 | * unknown BUT is needed to set data rate and to calculate timeouts. | ||
1177 | */ | ||
1178 | TRACE_CATCH(ftape_calibrate_data_rate(p->ft_qicstd&QIC_TAPE_STD_MASK), | ||
1179 | _res = -EINVAL); | ||
1180 | |||
1181 | /* The following will also recalcualte the timeouts for the tape | ||
1182 | * length and QIC std we want to format to. | ||
1183 | * abort with -EINVAL rather than -EIO | ||
1184 | */ | ||
1185 | SET_TRACE_LEVEL(ft_t_warn); | ||
1186 | TRACE_CATCH(ftape_decode_header_segment(hseg_buf), | ||
1187 | SET_TRACE_LEVEL(old_level); _res = -EINVAL); | ||
1188 | SET_TRACE_LEVEL(old_level); | ||
1189 | TRACE_EXIT 0; | ||
1190 | } | ||
1191 | |||
1192 | /* | ||
1193 | * Return the internal SOFTWARE status of the kernel driver. This does | ||
1194 | * NOT query the tape drive about its status. | ||
1195 | */ | ||
1196 | static int get_format_parms(struct ftfmtparms *p, __u8 *hseg_buffer) | ||
1197 | { | ||
1198 | TRACE_FUN(ft_t_flow); | ||
1199 | |||
1200 | TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_GETPARMS"); | ||
1201 | p->ft_qicstd = ft_qic_std; | ||
1202 | p->ft_fmtcode = ft_format_code; | ||
1203 | p->ft_fhm = hseg_buffer[FT_FHM]; | ||
1204 | p->ft_ftm = hseg_buffer[FT_FTM]; | ||
1205 | p->ft_spt = ft_segments_per_track; | ||
1206 | p->ft_tpc = ft_tracks_per_tape; | ||
1207 | TRACE_EXIT 0; | ||
1208 | } | ||
1209 | |||
1210 | static int mtiocftformat(struct mtftformat *mtftformat, int arg_size) | ||
1211 | { | ||
1212 | int result; | ||
1213 | union fmt_arg *arg = &mtftformat->fmt_arg; | ||
1214 | TRACE_FUN(ft_t_flow); | ||
1215 | |||
1216 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTFORMAT"); | ||
1217 | if (zft_offline) { | ||
1218 | if (ft_no_tape) { | ||
1219 | TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); | ||
1220 | } else { | ||
1221 | TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); | ||
1222 | } | ||
1223 | } | ||
1224 | if (zft_qic_mode) { | ||
1225 | TRACE_ABORT(-EACCES, ft_t_info, | ||
1226 | "driver needs to be in raw mode for this ioctl"); | ||
1227 | } | ||
1228 | if (zft_hseg_buf == NULL) { | ||
1229 | TRACE_CATCH(zft_vcalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); | ||
1230 | } | ||
1231 | zft_header_read = 0; | ||
1232 | switch(mtftformat->fmt_op) { | ||
1233 | case FTFMT_SET_PARMS: | ||
1234 | TRACE_CATCH(set_format_parms(&arg->fmt_parms, zft_hseg_buf),); | ||
1235 | TRACE_EXIT 0; | ||
1236 | case FTFMT_GET_PARMS: | ||
1237 | TRACE_CATCH(get_format_parms(&arg->fmt_parms, zft_hseg_buf),); | ||
1238 | TRACE_EXIT 0; | ||
1239 | case FTFMT_FORMAT_TRACK: | ||
1240 | if ((ft_formatted && zft_check_write_access(&zft_pos) < 0) || | ||
1241 | (!ft_formatted && zft_write_protected)) { | ||
1242 | TRACE_ABORT(-EACCES, ft_t_info, "Write access denied"); | ||
1243 | } | ||
1244 | TRACE_CATCH(ftape_format_track(arg->fmt_track.ft_track, | ||
1245 | arg->fmt_track.ft_gap3),); | ||
1246 | TRACE_EXIT 0; | ||
1247 | case FTFMT_STATUS: | ||
1248 | TRACE_CATCH(ftape_format_status(&arg->fmt_status.ft_segment),); | ||
1249 | TRACE_EXIT 0; | ||
1250 | case FTFMT_VERIFY: | ||
1251 | TRACE_CATCH(ftape_verify_segment(arg->fmt_verify.ft_segment, | ||
1252 | (SectorMap *)&arg->fmt_verify.ft_bsm),); | ||
1253 | TRACE_EXIT 0; | ||
1254 | default: | ||
1255 | TRACE_ABORT(-EINVAL, ft_t_err, "Invalid format operation"); | ||
1256 | } | ||
1257 | TRACE_EXIT result; | ||
1258 | } | ||
1259 | #endif | ||
1260 | |||
1261 | #ifdef MTIOCFTCMD | ||
1262 | /* | ||
1263 | * send a QIC-117 command to the drive, with optional timeouts, | ||
1264 | * parameter and result bits. This is intended to be used together | ||
1265 | * with the formatting ioctl. | ||
1266 | */ | ||
1267 | static int mtiocftcmd(struct mtftcmd *ftcmd, int arg_size) | ||
1268 | { | ||
1269 | int i; | ||
1270 | TRACE_FUN(ft_t_flow); | ||
1271 | |||
1272 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTCMD"); | ||
1273 | if (!capable(CAP_SYS_ADMIN)) { | ||
1274 | TRACE_ABORT(-EPERM, ft_t_info, | ||
1275 | "need CAP_SYS_ADMIN capability to send raw qic-117 commands"); | ||
1276 | } | ||
1277 | if (zft_qic_mode) { | ||
1278 | TRACE_ABORT(-EACCES, ft_t_info, | ||
1279 | "driver needs to be in raw mode for this ioctl"); | ||
1280 | } | ||
1281 | if (arg_size != sizeof(struct mtftcmd)) { | ||
1282 | TRACE_ABORT(-EINVAL, | ||
1283 | ft_t_info, "bad argument size: %d", arg_size); | ||
1284 | } | ||
1285 | if (ftcmd->ft_wait_before) { | ||
1286 | TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_before, | ||
1287 | &ftcmd->ft_status),); | ||
1288 | } | ||
1289 | if (ftcmd->ft_status & QIC_STATUS_ERROR) | ||
1290 | goto ftmtcmd_error; | ||
1291 | if (ftcmd->ft_result_bits != 0) { | ||
1292 | TRACE_CATCH(ftape_report_operation(&ftcmd->ft_result, | ||
1293 | ftcmd->ft_cmd, | ||
1294 | ftcmd->ft_result_bits),); | ||
1295 | } else { | ||
1296 | TRACE_CATCH(ftape_command(ftcmd->ft_cmd),); | ||
1297 | if (ftcmd->ft_status & QIC_STATUS_ERROR) | ||
1298 | goto ftmtcmd_error; | ||
1299 | for (i = 0; i < ftcmd->ft_parm_cnt; i++) { | ||
1300 | TRACE_CATCH(ftape_parameter(ftcmd->ft_parms[i]&0x0f),); | ||
1301 | if (ftcmd->ft_status & QIC_STATUS_ERROR) | ||
1302 | goto ftmtcmd_error; | ||
1303 | } | ||
1304 | } | ||
1305 | if (ftcmd->ft_wait_after != 0) { | ||
1306 | TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_after, | ||
1307 | &ftcmd->ft_status),); | ||
1308 | } | ||
1309 | ftmtcmd_error: | ||
1310 | if (ftcmd->ft_status & QIC_STATUS_ERROR) { | ||
1311 | TRACE(ft_t_noise, "error status set"); | ||
1312 | TRACE_CATCH(ftape_report_error(&ftcmd->ft_error, | ||
1313 | &ftcmd->ft_cmd, 1),); | ||
1314 | } | ||
1315 | TRACE_EXIT 0; /* this is not an i/o error */ | ||
1316 | } | ||
1317 | #endif | ||
1318 | |||
1319 | /* IOCTL routine called by kernel-interface code | ||
1320 | */ | ||
1321 | int _zft_ioctl(unsigned int command, void __user * arg) | ||
1322 | { | ||
1323 | int result; | ||
1324 | union { struct mtop mtop; | ||
1325 | struct mtget mtget; | ||
1326 | struct mtpos mtpos; | ||
1327 | #ifdef MTIOCRDFTSEG | ||
1328 | struct mtftseg mtftseg; | ||
1329 | #endif | ||
1330 | #ifdef MTIOCVOLINFO | ||
1331 | struct mtvolinfo mtvolinfo; | ||
1332 | #endif | ||
1333 | #ifdef MTIOCGETSIZE | ||
1334 | struct mttapesize mttapesize; | ||
1335 | #endif | ||
1336 | #ifdef MTIOCFTFORMAT | ||
1337 | struct mtftformat mtftformat; | ||
1338 | #endif | ||
1339 | #ifdef ZFT_OBSOLETE | ||
1340 | struct mtblksz mtblksz; | ||
1341 | #endif | ||
1342 | #ifdef MTIOCFTCMD | ||
1343 | struct mtftcmd mtftcmd; | ||
1344 | #endif | ||
1345 | } krnl_arg; | ||
1346 | int arg_size = _IOC_SIZE(command); | ||
1347 | int dir = _IOC_DIR(command); | ||
1348 | TRACE_FUN(ft_t_flow); | ||
1349 | |||
1350 | /* This check will only catch arguments that are too large ! | ||
1351 | */ | ||
1352 | if (dir & (_IOC_READ | _IOC_WRITE) && arg_size > sizeof(krnl_arg)) { | ||
1353 | TRACE_ABORT(-EINVAL, | ||
1354 | ft_t_info, "bad argument size: %d", arg_size); | ||
1355 | } | ||
1356 | if (dir & _IOC_WRITE) { | ||
1357 | if (copy_from_user(&krnl_arg, arg, arg_size) != 0) { | ||
1358 | TRACE_EXIT -EFAULT; | ||
1359 | } | ||
1360 | } | ||
1361 | TRACE(ft_t_flow, "called with ioctl command: 0x%08x", command); | ||
1362 | switch (command) { | ||
1363 | case MTIOCTOP: | ||
1364 | result = mtioctop(&krnl_arg.mtop, arg_size); | ||
1365 | break; | ||
1366 | case MTIOCGET: | ||
1367 | result = mtiocget(&krnl_arg.mtget, arg_size); | ||
1368 | break; | ||
1369 | case MTIOCPOS: | ||
1370 | result = mtiocpos(&krnl_arg.mtpos, arg_size); | ||
1371 | break; | ||
1372 | #ifdef MTIOCVOLINFO | ||
1373 | case MTIOCVOLINFO: | ||
1374 | result = mtiocvolinfo(&krnl_arg.mtvolinfo, arg_size); | ||
1375 | break; | ||
1376 | #endif | ||
1377 | #ifdef ZFT_OBSOLETE | ||
1378 | case MTIOC_ZFTAPE_GETBLKSZ: | ||
1379 | result = mtioc_zftape_getblksz(&krnl_arg.mtblksz, arg_size); | ||
1380 | break; | ||
1381 | #endif | ||
1382 | #ifdef MTIOCRDFTSEG | ||
1383 | case MTIOCRDFTSEG: /* read a segment via ioctl */ | ||
1384 | result = mtiocrdftseg(&krnl_arg.mtftseg, arg_size); | ||
1385 | break; | ||
1386 | #endif | ||
1387 | #ifdef MTIOCWRFTSEG | ||
1388 | case MTIOCWRFTSEG: /* write a segment via ioctl */ | ||
1389 | result = mtiocwrftseg(&krnl_arg.mtftseg, arg_size); | ||
1390 | break; | ||
1391 | #endif | ||
1392 | #ifdef MTIOCGETSIZE | ||
1393 | case MTIOCGETSIZE: | ||
1394 | result = mtiocgetsize(&krnl_arg.mttapesize, arg_size); | ||
1395 | break; | ||
1396 | #endif | ||
1397 | #ifdef MTIOCFTFORMAT | ||
1398 | case MTIOCFTFORMAT: | ||
1399 | result = mtiocftformat(&krnl_arg.mtftformat, arg_size); | ||
1400 | break; | ||
1401 | #endif | ||
1402 | #ifdef MTIOCFTCMD | ||
1403 | case MTIOCFTCMD: | ||
1404 | result = mtiocftcmd(&krnl_arg.mtftcmd, arg_size); | ||
1405 | break; | ||
1406 | #endif | ||
1407 | default: | ||
1408 | result = -EINVAL; | ||
1409 | break; | ||
1410 | } | ||
1411 | if ((result >= 0) && (dir & _IOC_READ)) { | ||
1412 | if (copy_to_user(arg, &krnl_arg, arg_size) != 0) { | ||
1413 | TRACE_EXIT -EFAULT; | ||
1414 | } | ||
1415 | } | ||
1416 | TRACE_EXIT result; | ||
1417 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-ctl.h b/drivers/char/ftape/zftape/zftape-ctl.h deleted file mode 100644 index 8e6f2d7ac74e..000000000000 --- a/drivers/char/ftape/zftape/zftape-ctl.h +++ /dev/null | |||
@@ -1,58 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_CTL_H | ||
2 | #define _ZFTAPE_CTL_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/zftape/zftape-ctl.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:02 $ | ||
25 | * | ||
26 | * This file contains the non-standard IOCTL related definitions | ||
27 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
28 | */ | ||
29 | |||
30 | #include <linux/ioctl.h> | ||
31 | #include <linux/mtio.h> | ||
32 | |||
33 | #include "../zftape/zftape-rw.h" | ||
34 | |||
35 | #ifdef CONFIG_ZFTAPE_MODULE | ||
36 | #define ftape_status (*zft_status) | ||
37 | #endif | ||
38 | |||
39 | extern int zft_offline; | ||
40 | extern int zft_mt_compression; | ||
41 | extern int zft_write_protected; | ||
42 | extern int zft_header_read; | ||
43 | extern unsigned int zft_unit; | ||
44 | extern int zft_resid; | ||
45 | |||
46 | extern void zft_reset_position(zft_position *pos); | ||
47 | extern int zft_check_write_access(zft_position *pos); | ||
48 | extern int zft_def_idle_state(void); | ||
49 | |||
50 | /* hooks for the VFS interface | ||
51 | */ | ||
52 | extern int _zft_open(unsigned int dev_minor, unsigned int access_mode); | ||
53 | extern int _zft_close(void); | ||
54 | extern int _zft_ioctl(unsigned int command, void __user *arg); | ||
55 | #endif | ||
56 | |||
57 | |||
58 | |||
diff --git a/drivers/char/ftape/zftape/zftape-eof.c b/drivers/char/ftape/zftape/zftape-eof.c deleted file mode 100644 index dcadcaee9ac1..000000000000 --- a/drivers/char/ftape/zftape/zftape-eof.c +++ /dev/null | |||
@@ -1,199 +0,0 @@ | |||
1 | /* | ||
2 | * I use these routines just to decide when I have to fake a | ||
3 | * volume-table to preserve compatibility to original ftape. | ||
4 | */ | ||
5 | /* | ||
6 | * Copyright (C) 1994-1995 Bas Laarhoven. | ||
7 | * | ||
8 | * Modified for zftape 1996, 1997 Claus Heine. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2, or (at your option) | ||
13 | any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU 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, USA. | ||
23 | |||
24 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.c,v $ | ||
25 | * $Revision: 1.2 $ | ||
26 | * $Date: 1997/10/05 19:19:02 $ | ||
27 | * | ||
28 | * This file contains the eof mark handling code | ||
29 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
30 | */ | ||
31 | |||
32 | #include <linux/string.h> | ||
33 | #include <linux/errno.h> | ||
34 | |||
35 | #include <linux/zftape.h> | ||
36 | |||
37 | #include "../zftape/zftape-init.h" | ||
38 | #include "../zftape/zftape-rw.h" | ||
39 | #include "../zftape/zftape-eof.h" | ||
40 | |||
41 | /* Global vars. | ||
42 | */ | ||
43 | |||
44 | /* a copy of the failed sector log from the header segment. | ||
45 | */ | ||
46 | eof_mark_union *zft_eof_map; | ||
47 | |||
48 | /* number of eof marks (entries in bad sector log) on tape. | ||
49 | */ | ||
50 | int zft_nr_eof_marks = -1; | ||
51 | |||
52 | |||
53 | /* Local vars. | ||
54 | */ | ||
55 | |||
56 | static char linux_tape_label[] = "Linux raw format V"; | ||
57 | enum { | ||
58 | min_fmt_version = 1, max_fmt_version = 2 | ||
59 | }; | ||
60 | static unsigned ftape_fmt_version = 0; | ||
61 | |||
62 | |||
63 | /* Ftape (mis)uses the bad sector log to record end-of-file marks. | ||
64 | * Initially (when the tape is erased) all entries in the bad sector | ||
65 | * log are added to the tape's bad sector map. The bad sector log then | ||
66 | * is cleared. | ||
67 | * | ||
68 | * The bad sector log normally contains entries of the form: | ||
69 | * even 16-bit word: segment number of bad sector | ||
70 | * odd 16-bit word: encoded date | ||
71 | * There can be a total of 448 entries (1792 bytes). | ||
72 | * | ||
73 | * My guess is that no program is using this bad sector log (the * | ||
74 | * format seems useless as there is no indication of the bad sector | ||
75 | * itself, only the segment) However, if any program does use the bad | ||
76 | * sector log, the format used by ftape will let the program think | ||
77 | * there are some bad sectors and no harm is done. | ||
78 | * | ||
79 | * The eof mark entries that ftape stores in the bad sector log: even | ||
80 | * 16-bit word: segment number of eof mark odd 16-bit word: sector | ||
81 | * number of eof mark [1..32] | ||
82 | * | ||
83 | * The zft_eof_map as maintained is a sorted list of eof mark entries. | ||
84 | * | ||
85 | * | ||
86 | * The tape name field in the header segments is used to store a linux | ||
87 | * tape identification string and a version number. This way the tape | ||
88 | * can be recognized as a Linux raw format tape when using tools under | ||
89 | * other OS's. | ||
90 | * | ||
91 | * 'Wide' QIC tapes (format code 4) don't have a failed sector list | ||
92 | * anymore. That space is used for the (longer) bad sector map that | ||
93 | * now is a variable length list too. We now store our end-of-file | ||
94 | * marker list after the bad-sector-map on tape. The list is delimited | ||
95 | * by a (__u32) 0 entry. | ||
96 | */ | ||
97 | |||
98 | int zft_ftape_validate_label(char *label) | ||
99 | { | ||
100 | static char tmp_label[45]; | ||
101 | int result = 0; | ||
102 | TRACE_FUN(ft_t_any); | ||
103 | |||
104 | memcpy(tmp_label, label, FT_LABEL_SZ); | ||
105 | tmp_label[FT_LABEL_SZ] = '\0'; | ||
106 | TRACE(ft_t_noise, "tape label = `%s'", tmp_label); | ||
107 | ftape_fmt_version = 0; | ||
108 | if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) { | ||
109 | int pos = strlen(linux_tape_label); | ||
110 | while (label[pos] >= '0' && label[pos] <= '9') { | ||
111 | ftape_fmt_version *= 10; | ||
112 | ftape_fmt_version = label[ pos++] - '0'; | ||
113 | } | ||
114 | result = (ftape_fmt_version >= min_fmt_version && | ||
115 | ftape_fmt_version <= max_fmt_version); | ||
116 | } | ||
117 | TRACE(ft_t_noise, "format version = %d", ftape_fmt_version); | ||
118 | TRACE_EXIT result; | ||
119 | } | ||
120 | |||
121 | static __u8 * find_end_of_eof_list(__u8 * ptr, __u8 * limit) | ||
122 | { | ||
123 | while (ptr + 3 < limit) { | ||
124 | |||
125 | if (get_unaligned((__u32*)ptr)) { | ||
126 | ptr += sizeof(__u32); | ||
127 | } else { | ||
128 | return ptr; | ||
129 | } | ||
130 | } | ||
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | void zft_ftape_extract_file_marks(__u8* address) | ||
135 | { | ||
136 | int i; | ||
137 | TRACE_FUN(ft_t_any); | ||
138 | |||
139 | zft_eof_map = NULL; | ||
140 | if (ft_format_code == fmt_var || ft_format_code == fmt_big) { | ||
141 | __u8* end; | ||
142 | __u8* start = ftape_find_end_of_bsm_list(address); | ||
143 | |||
144 | zft_nr_eof_marks = 0; | ||
145 | if (start) { | ||
146 | start += 3; /* skip end of list mark */ | ||
147 | end = find_end_of_eof_list(start, | ||
148 | address + FT_SEGMENT_SIZE); | ||
149 | if (end && end - start <= FT_FSL_SIZE) { | ||
150 | zft_nr_eof_marks = ((end - start) / | ||
151 | sizeof(eof_mark_union)); | ||
152 | zft_eof_map = (eof_mark_union *)start; | ||
153 | } else { | ||
154 | TRACE(ft_t_err, | ||
155 | "EOF Mark List is too long or damaged!"); | ||
156 | } | ||
157 | } else { | ||
158 | TRACE(ft_t_err, | ||
159 | "Bad Sector List is too long or damaged !"); | ||
160 | } | ||
161 | } else { | ||
162 | zft_eof_map = (eof_mark_union *)&address[FT_FSL]; | ||
163 | zft_nr_eof_marks = GET2(address, FT_FSL_CNT); | ||
164 | } | ||
165 | TRACE(ft_t_noise, "number of file marks: %d", zft_nr_eof_marks); | ||
166 | if (ftape_fmt_version == 1) { | ||
167 | TRACE(ft_t_info, "swapping version 1 fields"); | ||
168 | /* version 1 format uses swapped sector and segment | ||
169 | * fields, correct that ! | ||
170 | */ | ||
171 | for (i = 0; i < zft_nr_eof_marks; ++i) { | ||
172 | __u16 tmp = GET2(&zft_eof_map[i].mark.segment,0); | ||
173 | PUT2(&zft_eof_map[i].mark.segment, 0, | ||
174 | GET2(&zft_eof_map[i].mark.date,0)); | ||
175 | PUT2(&zft_eof_map[i].mark.date, 0, tmp); | ||
176 | } | ||
177 | } | ||
178 | for (i = 0; i < zft_nr_eof_marks; ++i) { | ||
179 | TRACE(ft_t_noise, "eof mark: %5d/%2d", | ||
180 | GET2(&zft_eof_map[i].mark.segment, 0), | ||
181 | GET2(&zft_eof_map[i].mark.date,0)); | ||
182 | } | ||
183 | TRACE_EXIT; | ||
184 | } | ||
185 | |||
186 | void zft_clear_ftape_file_marks(void) | ||
187 | { | ||
188 | TRACE_FUN(ft_t_flow); | ||
189 | /* Clear failed sector log: remove all tape marks. We | ||
190 | * don't use old ftape-style EOF-marks. | ||
191 | */ | ||
192 | TRACE(ft_t_info, "Clearing old ftape's eof map"); | ||
193 | memset(zft_eof_map, 0, zft_nr_eof_marks * sizeof(__u32)); | ||
194 | zft_nr_eof_marks = 0; | ||
195 | PUT2(zft_hseg_buf, FT_FSL_CNT, 0); /* nr of eof-marks */ | ||
196 | zft_header_changed = 1; | ||
197 | zft_update_label(zft_hseg_buf); | ||
198 | TRACE_EXIT; | ||
199 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-eof.h b/drivers/char/ftape/zftape/zftape-eof.h deleted file mode 100644 index 26568c26c518..000000000000 --- a/drivers/char/ftape/zftape/zftape-eof.h +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_EOF_H | ||
2 | #define _ZFTAPE_EOF_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1995 Bas Laarhoven. | ||
6 | * adaptaed for zftape 1996, 1997 by Claus 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/zftape/zftape-eof.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:19:03 $ | ||
26 | * | ||
27 | * Definitions and declarations for the end of file markers | ||
28 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
29 | */ | ||
30 | |||
31 | #include <linux/ftape-header-segment.h> | ||
32 | #include "../zftape/zftape-buffers.h" | ||
33 | /* failed sector log size (only used if format code != 4). | ||
34 | */ | ||
35 | |||
36 | typedef union { | ||
37 | ft_fsl_entry mark; | ||
38 | __u32 entry; | ||
39 | } eof_mark_union; | ||
40 | |||
41 | /* ftape-eof.c defined global vars. | ||
42 | */ | ||
43 | extern int zft_nr_eof_marks; | ||
44 | extern eof_mark_union *zft_eof_map; | ||
45 | |||
46 | /* ftape-eof.c defined global functions. | ||
47 | */ | ||
48 | extern void zft_ftape_extract_file_marks(__u8* address); | ||
49 | extern int zft_ftape_validate_label(char* label); | ||
50 | extern void zft_clear_ftape_file_marks(void); | ||
51 | |||
52 | #endif | ||
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c deleted file mode 100644 index 164a1aa77a2f..000000000000 --- a/drivers/char/ftape/zftape/zftape-init.c +++ /dev/null | |||
@@ -1,377 +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 | * This file contains the code that registers the zftape frontend | ||
20 | * to the ftape floppy tape driver for Linux | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/fs.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/signal.h> | ||
28 | #include <linux/major.h> | ||
29 | #include <linux/slab.h> | ||
30 | #ifdef CONFIG_KMOD | ||
31 | #include <linux/kmod.h> | ||
32 | #endif | ||
33 | #include <linux/fcntl.h> | ||
34 | #include <linux/smp_lock.h> | ||
35 | |||
36 | #include <linux/zftape.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/device.h> | ||
39 | |||
40 | #include "../zftape/zftape-init.h" | ||
41 | #include "../zftape/zftape-read.h" | ||
42 | #include "../zftape/zftape-write.h" | ||
43 | #include "../zftape/zftape-ctl.h" | ||
44 | #include "../zftape/zftape-buffers.h" | ||
45 | |||
46 | MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine " | ||
47 | "(claus@momo.math.rwth-aachen.de)"); | ||
48 | MODULE_DESCRIPTION(ZFTAPE_VERSION " - " | ||
49 | "VFS interface for the Linux floppy tape driver. " | ||
50 | "Support for QIC-113 compatible volume table " | ||
51 | "and builtin compression (lzrw3 algorithm)"); | ||
52 | MODULE_SUPPORTED_DEVICE("char-major-27"); | ||
53 | MODULE_LICENSE("GPL"); | ||
54 | |||
55 | /* Global vars. | ||
56 | */ | ||
57 | struct zft_cmpr_ops *zft_cmpr_ops = NULL; | ||
58 | const ftape_info *zft_status; | ||
59 | |||
60 | /* Local vars. | ||
61 | */ | ||
62 | static unsigned long busy_flag; | ||
63 | |||
64 | static sigset_t orig_sigmask; | ||
65 | |||
66 | /* the interface to the kernel vfs layer | ||
67 | */ | ||
68 | |||
69 | /* Note about llseek(): | ||
70 | * | ||
71 | * st.c and tpqic.c update fp->f_pos but don't implment llseek() and | ||
72 | * initialize the llseek component of the file_ops struct with NULL. | ||
73 | * This means that the user will get the default seek, but the tape | ||
74 | * device will not respect the new position, but happily read from the | ||
75 | * old position. Think a zftape specific llseek() function would be | ||
76 | * better, returning -ESPIPE. TODO. | ||
77 | */ | ||
78 | |||
79 | static int zft_open (struct inode *ino, struct file *filep); | ||
80 | static int zft_close(struct inode *ino, struct file *filep); | ||
81 | static int zft_ioctl(struct inode *ino, struct file *filep, | ||
82 | unsigned int command, unsigned long arg); | ||
83 | static int zft_mmap(struct file *filep, struct vm_area_struct *vma); | ||
84 | static ssize_t zft_read (struct file *fp, char __user *buff, | ||
85 | size_t req_len, loff_t *ppos); | ||
86 | static ssize_t zft_write(struct file *fp, const char __user *buff, | ||
87 | size_t req_len, loff_t *ppos); | ||
88 | |||
89 | static const struct file_operations zft_cdev = | ||
90 | { | ||
91 | .owner = THIS_MODULE, | ||
92 | .read = zft_read, | ||
93 | .write = zft_write, | ||
94 | .ioctl = zft_ioctl, | ||
95 | .mmap = zft_mmap, | ||
96 | .open = zft_open, | ||
97 | .release = zft_close, | ||
98 | }; | ||
99 | |||
100 | static struct class *zft_class; | ||
101 | |||
102 | /* Open floppy tape device | ||
103 | */ | ||
104 | static int zft_open(struct inode *ino, struct file *filep) | ||
105 | { | ||
106 | int result; | ||
107 | TRACE_FUN(ft_t_flow); | ||
108 | |||
109 | nonseekable_open(ino, filep); | ||
110 | TRACE(ft_t_flow, "called for minor %d", iminor(ino)); | ||
111 | if ( test_and_set_bit(0,&busy_flag) ) { | ||
112 | TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy"); | ||
113 | } | ||
114 | if ((iminor(ino) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND)) | ||
115 | > | ||
116 | FTAPE_SEL_D) { | ||
117 | clear_bit(0,&busy_flag); | ||
118 | TRACE_ABORT(-ENXIO, ft_t_err, "failed: invalid unit nr"); | ||
119 | } | ||
120 | orig_sigmask = current->blocked; | ||
121 | sigfillset(¤t->blocked); | ||
122 | result = _zft_open(iminor(ino), filep->f_flags & O_ACCMODE); | ||
123 | if (result < 0) { | ||
124 | current->blocked = orig_sigmask; /* restore mask */ | ||
125 | clear_bit(0,&busy_flag); | ||
126 | TRACE_ABORT(result, ft_t_err, "_ftape_open failed"); | ||
127 | } else { | ||
128 | /* Mask signals that will disturb proper operation of the | ||
129 | * program that is calling. | ||
130 | */ | ||
131 | current->blocked = orig_sigmask; | ||
132 | sigaddsetmask (¤t->blocked, _DO_BLOCK); | ||
133 | TRACE_EXIT 0; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* Close floppy tape device | ||
138 | */ | ||
139 | static int zft_close(struct inode *ino, struct file *filep) | ||
140 | { | ||
141 | int result; | ||
142 | TRACE_FUN(ft_t_flow); | ||
143 | |||
144 | if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit) { | ||
145 | TRACE(ft_t_err, "failed: not busy or wrong unit"); | ||
146 | TRACE_EXIT 0; | ||
147 | } | ||
148 | sigfillset(¤t->blocked); | ||
149 | result = _zft_close(); | ||
150 | if (result < 0) { | ||
151 | TRACE(ft_t_err, "_zft_close failed"); | ||
152 | } | ||
153 | current->blocked = orig_sigmask; /* restore before open state */ | ||
154 | clear_bit(0,&busy_flag); | ||
155 | TRACE_EXIT 0; | ||
156 | } | ||
157 | |||
158 | /* Ioctl for floppy tape device | ||
159 | */ | ||
160 | static int zft_ioctl(struct inode *ino, struct file *filep, | ||
161 | unsigned int command, unsigned long arg) | ||
162 | { | ||
163 | int result = -EIO; | ||
164 | sigset_t old_sigmask; | ||
165 | TRACE_FUN(ft_t_flow); | ||
166 | |||
167 | if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { | ||
168 | TRACE_ABORT(-EIO, ft_t_err, | ||
169 | "failed: not busy, failure or wrong unit"); | ||
170 | } | ||
171 | old_sigmask = current->blocked; /* save mask */ | ||
172 | sigfillset(¤t->blocked); | ||
173 | /* This will work as long as sizeof(void *) == sizeof(long) */ | ||
174 | result = _zft_ioctl(command, (void __user *) arg); | ||
175 | current->blocked = old_sigmask; /* restore mask */ | ||
176 | TRACE_EXIT result; | ||
177 | } | ||
178 | |||
179 | /* Ioctl for floppy tape device | ||
180 | */ | ||
181 | static int zft_mmap(struct file *filep, struct vm_area_struct *vma) | ||
182 | { | ||
183 | int result = -EIO; | ||
184 | sigset_t old_sigmask; | ||
185 | TRACE_FUN(ft_t_flow); | ||
186 | |||
187 | if ( !test_bit(0,&busy_flag) || | ||
188 | iminor(filep->f_dentry->d_inode) != zft_unit || | ||
189 | ft_failure) | ||
190 | { | ||
191 | TRACE_ABORT(-EIO, ft_t_err, | ||
192 | "failed: not busy, failure or wrong unit"); | ||
193 | } | ||
194 | old_sigmask = current->blocked; /* save mask */ | ||
195 | sigfillset(¤t->blocked); | ||
196 | if ((result = ftape_mmap(vma)) >= 0) { | ||
197 | #ifndef MSYNC_BUG_WAS_FIXED | ||
198 | static struct vm_operations_struct dummy = { NULL, }; | ||
199 | vma->vm_ops = &dummy; | ||
200 | #endif | ||
201 | } | ||
202 | current->blocked = old_sigmask; /* restore mask */ | ||
203 | TRACE_EXIT result; | ||
204 | } | ||
205 | |||
206 | /* Read from floppy tape device | ||
207 | */ | ||
208 | static ssize_t zft_read(struct file *fp, char __user *buff, | ||
209 | size_t req_len, loff_t *ppos) | ||
210 | { | ||
211 | int result = -EIO; | ||
212 | sigset_t old_sigmask; | ||
213 | struct inode *ino = fp->f_dentry->d_inode; | ||
214 | TRACE_FUN(ft_t_flow); | ||
215 | |||
216 | TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len); | ||
217 | if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { | ||
218 | TRACE_ABORT(-EIO, ft_t_err, | ||
219 | "failed: not busy, failure or wrong unit"); | ||
220 | } | ||
221 | old_sigmask = current->blocked; /* save mask */ | ||
222 | sigfillset(¤t->blocked); | ||
223 | result = _zft_read(buff, req_len); | ||
224 | current->blocked = old_sigmask; /* restore mask */ | ||
225 | TRACE(ft_t_data_flow, "return with count: %d", result); | ||
226 | TRACE_EXIT result; | ||
227 | } | ||
228 | |||
229 | /* Write to tape device | ||
230 | */ | ||
231 | static ssize_t zft_write(struct file *fp, const char __user *buff, | ||
232 | size_t req_len, loff_t *ppos) | ||
233 | { | ||
234 | int result = -EIO; | ||
235 | sigset_t old_sigmask; | ||
236 | struct inode *ino = fp->f_dentry->d_inode; | ||
237 | TRACE_FUN(ft_t_flow); | ||
238 | |||
239 | TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len); | ||
240 | if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { | ||
241 | TRACE_ABORT(-EIO, ft_t_err, | ||
242 | "failed: not busy, failure or wrong unit"); | ||
243 | } | ||
244 | old_sigmask = current->blocked; /* save mask */ | ||
245 | sigfillset(¤t->blocked); | ||
246 | result = _zft_write(buff, req_len); | ||
247 | current->blocked = old_sigmask; /* restore mask */ | ||
248 | TRACE(ft_t_data_flow, "return with count: %d", result); | ||
249 | TRACE_EXIT result; | ||
250 | } | ||
251 | |||
252 | /* END OF VFS INTERFACE | ||
253 | * | ||
254 | *****************************************************************************/ | ||
255 | |||
256 | /* driver/module initialization | ||
257 | */ | ||
258 | |||
259 | /* the compression module has to call this function to hook into the zftape | ||
260 | * code | ||
261 | */ | ||
262 | int zft_cmpr_register(struct zft_cmpr_ops *new_ops) | ||
263 | { | ||
264 | TRACE_FUN(ft_t_flow); | ||
265 | |||
266 | if (zft_cmpr_ops != NULL) { | ||
267 | TRACE_EXIT -EBUSY; | ||
268 | } else { | ||
269 | zft_cmpr_ops = new_ops; | ||
270 | TRACE_EXIT 0; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | /* lock the zft-compressor() module. | ||
275 | */ | ||
276 | int zft_cmpr_lock(int try_to_load) | ||
277 | { | ||
278 | if (zft_cmpr_ops == NULL) { | ||
279 | #ifdef CONFIG_KMOD | ||
280 | if (try_to_load) { | ||
281 | request_module("zft-compressor"); | ||
282 | if (zft_cmpr_ops == NULL) { | ||
283 | return -ENOSYS; | ||
284 | } | ||
285 | } else { | ||
286 | return -ENOSYS; | ||
287 | } | ||
288 | #else | ||
289 | return -ENOSYS; | ||
290 | #endif | ||
291 | } | ||
292 | (*zft_cmpr_ops->lock)(); | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | #ifdef CONFIG_ZFT_COMPRESSOR | ||
297 | extern int zft_compressor_init(void); | ||
298 | #endif | ||
299 | |||
300 | /* Called by modules package when installing the driver or by kernel | ||
301 | * during the initialization phase | ||
302 | */ | ||
303 | int __init zft_init(void) | ||
304 | { | ||
305 | int i; | ||
306 | TRACE_FUN(ft_t_flow); | ||
307 | |||
308 | #ifdef MODULE | ||
309 | printk(KERN_INFO ZFTAPE_VERSION "\n"); | ||
310 | if (TRACE_LEVEL >= ft_t_info) { | ||
311 | printk( | ||
312 | KERN_INFO | ||
313 | "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" | ||
314 | KERN_INFO | ||
315 | "vfs interface for ftape floppy tape driver.\n" | ||
316 | KERN_INFO | ||
317 | "Support for QIC-113 compatible volume table, dynamic memory allocation\n" | ||
318 | KERN_INFO | ||
319 | "and builtin compression (lzrw3 algorithm).\n"); | ||
320 | } | ||
321 | #else /* !MODULE */ | ||
322 | /* print a short no-nonsense boot message */ | ||
323 | printk(KERN_INFO ZFTAPE_VERSION "\n"); | ||
324 | #endif /* MODULE */ | ||
325 | TRACE(ft_t_info, "zft_init @ 0x%p", zft_init); | ||
326 | TRACE(ft_t_info, | ||
327 | "installing zftape VFS interface for ftape driver ..."); | ||
328 | TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); | ||
329 | |||
330 | zft_class = class_create(THIS_MODULE, "zft"); | ||
331 | for (i = 0; i < 4; i++) { | ||
332 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); | ||
333 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); | ||
334 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); | ||
335 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); | ||
336 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); | ||
337 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); | ||
338 | } | ||
339 | |||
340 | #ifdef CONFIG_ZFT_COMPRESSOR | ||
341 | (void)zft_compressor_init(); | ||
342 | #endif | ||
343 | zft_status = ftape_get_status(); /* fetch global data of ftape | ||
344 | * hardware driver | ||
345 | */ | ||
346 | TRACE_EXIT 0; | ||
347 | } | ||
348 | |||
349 | |||
350 | /* Called by modules package when removing the driver | ||
351 | */ | ||
352 | static void zft_exit(void) | ||
353 | { | ||
354 | int i; | ||
355 | TRACE_FUN(ft_t_flow); | ||
356 | |||
357 | if (unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) { | ||
358 | TRACE(ft_t_warn, "failed"); | ||
359 | } else { | ||
360 | TRACE(ft_t_info, "successful"); | ||
361 | } | ||
362 | for (i = 0; i < 4; i++) { | ||
363 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i)); | ||
364 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4)); | ||
365 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16)); | ||
366 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20)); | ||
367 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32)); | ||
368 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36)); | ||
369 | } | ||
370 | class_destroy(zft_class); | ||
371 | zft_uninit_mem(); /* release remaining memory, if any */ | ||
372 | printk(KERN_INFO "zftape successfully unloaded.\n"); | ||
373 | TRACE_EXIT; | ||
374 | } | ||
375 | |||
376 | module_init(zft_init); | ||
377 | module_exit(zft_exit); | ||
diff --git a/drivers/char/ftape/zftape/zftape-init.h b/drivers/char/ftape/zftape/zftape-init.h deleted file mode 100644 index 937e5d48c20e..000000000000 --- a/drivers/char/ftape/zftape/zftape-init.h +++ /dev/null | |||
@@ -1,77 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_INIT_H | ||
2 | #define _ZFTAPE_INIT_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus 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/zftape/zftape-init.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:05 $ | ||
25 | * | ||
26 | * This file contains definitions and macro for the vfs | ||
27 | * interface defined by zftape | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/ftape-header-segment.h> | ||
32 | |||
33 | #include "../lowlevel/ftape-tracing.h" | ||
34 | #include "../lowlevel/ftape-ctl.h" | ||
35 | #include "../lowlevel/ftape-read.h" | ||
36 | #include "../lowlevel/ftape-write.h" | ||
37 | #include "../lowlevel/ftape-bsm.h" | ||
38 | #include "../lowlevel/ftape-io.h" | ||
39 | #include "../lowlevel/ftape-buffer.h" | ||
40 | #include "../lowlevel/ftape-format.h" | ||
41 | |||
42 | #include "../zftape/zftape-rw.h" | ||
43 | |||
44 | #ifdef MODULE | ||
45 | #define ftape_status (*zft_status) | ||
46 | #endif | ||
47 | |||
48 | extern const ftape_info *zft_status; /* needed for zftape-vtbl.h */ | ||
49 | |||
50 | #include "../zftape/zftape-vtbl.h" | ||
51 | |||
52 | struct zft_cmpr_ops { | ||
53 | int (*write)(int *write_cnt, | ||
54 | __u8 *dst_buf, const int seg_sz, | ||
55 | const __u8 __user *src_buf, const int req_len, | ||
56 | const zft_position *pos, const zft_volinfo *volume); | ||
57 | int (*read)(int *read_cnt, | ||
58 | __u8 __user *dst_buf, const int req_len, | ||
59 | const __u8 *src_buf, const int seg_sz, | ||
60 | const zft_position *pos, const zft_volinfo *volume); | ||
61 | int (*seek)(unsigned int new_block_pos, | ||
62 | zft_position *pos, const zft_volinfo *volume, | ||
63 | __u8 *buffer); | ||
64 | void (*lock) (void); | ||
65 | void (*reset) (void); | ||
66 | void (*cleanup)(void); | ||
67 | }; | ||
68 | |||
69 | extern struct zft_cmpr_ops *zft_cmpr_ops; | ||
70 | /* zftape-init.c defined global functions. | ||
71 | */ | ||
72 | extern int zft_cmpr_register(struct zft_cmpr_ops *new_ops); | ||
73 | extern int zft_cmpr_lock(int try_to_load); | ||
74 | |||
75 | #endif | ||
76 | |||
77 | |||
diff --git a/drivers/char/ftape/zftape/zftape-read.c b/drivers/char/ftape/zftape/zftape-read.c deleted file mode 100644 index 214bf03dce68..000000000000 --- a/drivers/char/ftape/zftape/zftape-read.c +++ /dev/null | |||
@@ -1,377 +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/zftape/zftape-read.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:19:06 $ | ||
22 | * | ||
23 | * This file contains the high level reading code | ||
24 | * for the QIC-117 floppy-tape driver for Linux. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | |||
30 | #include <linux/zftape.h> | ||
31 | |||
32 | #include <asm/uaccess.h> | ||
33 | |||
34 | #include "../zftape/zftape-init.h" | ||
35 | #include "../zftape/zftape-eof.h" | ||
36 | #include "../zftape/zftape-ctl.h" | ||
37 | #include "../zftape/zftape-write.h" | ||
38 | #include "../zftape/zftape-read.h" | ||
39 | #include "../zftape/zftape-rw.h" | ||
40 | #include "../zftape/zftape-vtbl.h" | ||
41 | |||
42 | /* Global vars. | ||
43 | */ | ||
44 | int zft_just_before_eof; | ||
45 | |||
46 | /* Local vars. | ||
47 | */ | ||
48 | static int buf_len_rd; | ||
49 | |||
50 | void zft_zap_read_buffers(void) | ||
51 | { | ||
52 | buf_len_rd = 0; | ||
53 | } | ||
54 | |||
55 | int zft_read_header_segments(void) | ||
56 | { | ||
57 | TRACE_FUN(ft_t_flow); | ||
58 | |||
59 | zft_header_read = 0; | ||
60 | TRACE_CATCH(zft_vmalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); | ||
61 | TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),); | ||
62 | TRACE(ft_t_info, "Segments written since first format: %d", | ||
63 | (int)GET4(zft_hseg_buf, FT_SEG_CNT)); | ||
64 | zft_qic113 = (ft_format_code != fmt_normal && | ||
65 | ft_format_code != fmt_1100ft && | ||
66 | ft_format_code != fmt_425ft); | ||
67 | TRACE(ft_t_info, "ft_first_data_segment: %d, ft_last_data_segment: %d", | ||
68 | ft_first_data_segment, ft_last_data_segment); | ||
69 | zft_capacity = zft_get_capacity(); | ||
70 | zft_old_ftape = zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]); | ||
71 | if (zft_old_ftape) { | ||
72 | TRACE(ft_t_info, | ||
73 | "Found old ftaped tape, emulating eof marks, entering read-only mode"); | ||
74 | zft_ftape_extract_file_marks(zft_hseg_buf); | ||
75 | TRACE_CATCH(zft_fake_volume_headers(zft_eof_map, | ||
76 | zft_nr_eof_marks),); | ||
77 | } else { | ||
78 | /* the specs say that the volume table must be | ||
79 | * initialized with zeroes during formatting, so it | ||
80 | * MUST be readable, i.e. contain vaid ECC | ||
81 | * information. | ||
82 | */ | ||
83 | TRACE_CATCH(ftape_read_segment(ft_first_data_segment, | ||
84 | zft_deblock_buf, | ||
85 | FT_RD_SINGLE),); | ||
86 | TRACE_CATCH(zft_extract_volume_headers(zft_deblock_buf),); | ||
87 | } | ||
88 | zft_header_read = 1; | ||
89 | zft_set_flags(zft_unit); | ||
90 | zft_reset_position(&zft_pos); | ||
91 | TRACE_EXIT 0; | ||
92 | } | ||
93 | |||
94 | int zft_fetch_segment_fraction(const unsigned int segment, void *buffer, | ||
95 | const ft_read_mode_t read_mode, | ||
96 | const unsigned int start, | ||
97 | const unsigned int size) | ||
98 | { | ||
99 | int seg_sz; | ||
100 | TRACE_FUN(ft_t_flow); | ||
101 | |||
102 | if (segment == zft_deblock_segment) { | ||
103 | TRACE(ft_t_data_flow, | ||
104 | "re-using segment %d already in deblock buffer", | ||
105 | segment); | ||
106 | seg_sz = zft_get_seg_sz(segment); | ||
107 | if (start > seg_sz) { | ||
108 | TRACE_ABORT(-EINVAL, ft_t_bug, | ||
109 | "trying to read beyond end of segment:\n" | ||
110 | KERN_INFO "seg_sz : %d\n" | ||
111 | KERN_INFO "start : %d\n" | ||
112 | KERN_INFO "segment: %d", | ||
113 | seg_sz, start, segment); | ||
114 | } | ||
115 | if ((start + size) > seg_sz) { | ||
116 | TRACE_EXIT seg_sz - start; | ||
117 | } | ||
118 | TRACE_EXIT size; | ||
119 | } | ||
120 | seg_sz = ftape_read_segment_fraction(segment, buffer, read_mode, | ||
121 | start, size); | ||
122 | TRACE(ft_t_data_flow, "segment %d, result %d", segment, seg_sz); | ||
123 | if ((int)seg_sz >= 0 && start == 0 && size == FT_SEGMENT_SIZE) { | ||
124 | /* this implicitly assumes that we are always called with | ||
125 | * buffer == zft_deblock_buf | ||
126 | */ | ||
127 | zft_deblock_segment = segment; | ||
128 | } else { | ||
129 | zft_deblock_segment = -1; | ||
130 | } | ||
131 | TRACE_EXIT seg_sz; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * out: | ||
136 | * | ||
137 | * int *read_cnt: the number of bytes we removed from the | ||
138 | * zft_deblock_buf (result) | ||
139 | * | ||
140 | * int *to_do : the remaining size of the read-request. Is changed. | ||
141 | * | ||
142 | * in: | ||
143 | * | ||
144 | * char *buff : buff is the address of the upper part of the user | ||
145 | * buffer, that hasn't been filled with data yet. | ||
146 | * int buf_pos_read: copy of buf_pos_rd | ||
147 | * int buf_len_read: copy of buf_len_rd | ||
148 | * char *zft_deblock_buf: ftape_zft_deblock_buf | ||
149 | * | ||
150 | * returns the amount of data actually copied to the user-buffer | ||
151 | * | ||
152 | * to_do MUST NOT SHRINK except to indicate an EOT. In this case to_do | ||
153 | * has to be set to 0. We cannot return -ENOSPC, because we return the | ||
154 | * amount of data actually * copied to the user-buffer | ||
155 | */ | ||
156 | static int zft_simple_read (int *read_cnt, | ||
157 | __u8 __user *dst_buf, | ||
158 | const int to_do, | ||
159 | const __u8 *src_buf, | ||
160 | const int seg_sz, | ||
161 | const zft_position *pos, | ||
162 | const zft_volinfo *volume) | ||
163 | { | ||
164 | TRACE_FUN(ft_t_flow); | ||
165 | |||
166 | if (seg_sz - pos->seg_byte_pos < to_do) { | ||
167 | *read_cnt = seg_sz - pos->seg_byte_pos; | ||
168 | } else { | ||
169 | *read_cnt = to_do; | ||
170 | } | ||
171 | if (copy_to_user(dst_buf, | ||
172 | src_buf + pos->seg_byte_pos, *read_cnt) != 0) { | ||
173 | TRACE_EXIT -EFAULT; | ||
174 | } | ||
175 | TRACE(ft_t_noise, "nr bytes just read: %d", *read_cnt); | ||
176 | TRACE_EXIT *read_cnt; | ||
177 | } | ||
178 | |||
179 | /* req_len: gets clipped due to EOT of EOF. | ||
180 | * req_clipped: is a flag indicating whether req_len was clipped or not | ||
181 | * volume: contains information on current volume (blk_sz etc.) | ||
182 | */ | ||
183 | static int check_read_access(int *req_len, | ||
184 | const zft_volinfo **volume, | ||
185 | int *req_clipped, | ||
186 | const zft_position *pos) | ||
187 | { | ||
188 | static __s64 remaining; | ||
189 | static int eod; | ||
190 | TRACE_FUN(ft_t_flow); | ||
191 | |||
192 | if (zft_io_state != zft_reading) { | ||
193 | if (zft_offline) { /* offline includes no_tape */ | ||
194 | TRACE_ABORT(-ENXIO, ft_t_warn, | ||
195 | "tape is offline or no cartridge"); | ||
196 | } | ||
197 | if (!ft_formatted) { | ||
198 | TRACE_ABORT(-EACCES, | ||
199 | ft_t_warn, "tape is not formatted"); | ||
200 | } | ||
201 | /* now enter defined state, read header segment if not | ||
202 | * already done and flush write buffers | ||
203 | */ | ||
204 | TRACE_CATCH(zft_def_idle_state(),); | ||
205 | zft_io_state = zft_reading; | ||
206 | if (zft_tape_at_eod(pos)) { | ||
207 | eod = 1; | ||
208 | TRACE_EXIT 1; | ||
209 | } | ||
210 | eod = 0; | ||
211 | *volume = zft_find_volume(pos->seg_pos); | ||
212 | /* get the space left until EOF */ | ||
213 | remaining = zft_check_for_eof(*volume, pos); | ||
214 | buf_len_rd = 0; | ||
215 | TRACE(ft_t_noise, "remaining: " LL_X ", vol_no: %d", | ||
216 | LL(remaining), (*volume)->count); | ||
217 | } else if (zft_tape_at_eod(pos)) { | ||
218 | if (++eod > 2) { | ||
219 | TRACE_EXIT -EIO; /* st.c also returns -EIO */ | ||
220 | } else { | ||
221 | TRACE_EXIT 1; | ||
222 | } | ||
223 | } | ||
224 | if ((*req_len % (*volume)->blk_sz) != 0) { | ||
225 | /* this message is informational only. The user gets the | ||
226 | * proper return value | ||
227 | */ | ||
228 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
229 | "req_len %d not a multiple of block size %d", | ||
230 | *req_len, (*volume)->blk_sz); | ||
231 | } | ||
232 | /* As GNU tar doesn't accept partial read counts when the | ||
233 | * multiple volume flag is set, we make sure to return the | ||
234 | * requested amount of data. Except, of course, at the end of | ||
235 | * the tape or file mark. | ||
236 | */ | ||
237 | remaining -= *req_len; | ||
238 | if (remaining <= 0) { | ||
239 | TRACE(ft_t_noise, | ||
240 | "clipped request from %d to %d.", | ||
241 | *req_len, (int)(*req_len + remaining)); | ||
242 | *req_len += remaining; | ||
243 | *req_clipped = 1; | ||
244 | } else { | ||
245 | *req_clipped = 0; | ||
246 | } | ||
247 | TRACE_EXIT 0; | ||
248 | } | ||
249 | |||
250 | /* this_segs_size: the current segment's size. | ||
251 | * buff: the USER-SPACE buffer provided by the calling function. | ||
252 | * req_len: how much data should be read at most. | ||
253 | * volume: contains information on current volume (blk_sz etc.) | ||
254 | */ | ||
255 | static int empty_deblock_buf(__u8 __user *usr_buf, const int req_len, | ||
256 | const __u8 *src_buf, const int seg_sz, | ||
257 | zft_position *pos, | ||
258 | const zft_volinfo *volume) | ||
259 | { | ||
260 | int cnt; | ||
261 | int result = 0; | ||
262 | TRACE_FUN(ft_t_flow); | ||
263 | |||
264 | TRACE(ft_t_data_flow, "this_segs_size: %d", seg_sz); | ||
265 | if (zft_use_compression && volume->use_compression) { | ||
266 | TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); | ||
267 | TRACE_CATCH(result= (*zft_cmpr_ops->read)(&cnt, | ||
268 | usr_buf, req_len, | ||
269 | src_buf, seg_sz, | ||
270 | pos, volume),); | ||
271 | } else { | ||
272 | TRACE_CATCH(result= zft_simple_read (&cnt, | ||
273 | usr_buf, req_len, | ||
274 | src_buf, seg_sz, | ||
275 | pos, volume),); | ||
276 | } | ||
277 | pos->volume_pos += result; | ||
278 | pos->tape_pos += cnt; | ||
279 | pos->seg_byte_pos += cnt; | ||
280 | buf_len_rd -= cnt; /* remaining bytes in buffer */ | ||
281 | TRACE(ft_t_data_flow, "buf_len_rd: %d, cnt: %d", buf_len_rd, cnt); | ||
282 | if(pos->seg_byte_pos >= seg_sz) { | ||
283 | pos->seg_pos++; | ||
284 | pos->seg_byte_pos = 0; | ||
285 | } | ||
286 | TRACE(ft_t_data_flow, "bytes moved out of deblock-buffer: %d", cnt); | ||
287 | TRACE_EXIT result; | ||
288 | } | ||
289 | |||
290 | |||
291 | /* note: we store the segment id of the segment that is inside the | ||
292 | * deblock buffer. This spares a lot of ftape_read_segment()s when we | ||
293 | * use small block-sizes. The block-size may be 1kb (SECTOR_SIZE). In | ||
294 | * this case a MTFSR 28 maybe still inside the same segment. | ||
295 | */ | ||
296 | int _zft_read(char __user *buff, int req_len) | ||
297 | { | ||
298 | int req_clipped; | ||
299 | int result = 0; | ||
300 | int bytes_read = 0; | ||
301 | static unsigned int seg_sz = 0; | ||
302 | static const zft_volinfo *volume = NULL; | ||
303 | TRACE_FUN(ft_t_flow); | ||
304 | |||
305 | zft_resid = req_len; | ||
306 | result = check_read_access(&req_len, &volume, | ||
307 | &req_clipped, &zft_pos); | ||
308 | switch(result) { | ||
309 | case 0: | ||
310 | break; /* nothing special */ | ||
311 | case 1: | ||
312 | TRACE(ft_t_noise, "EOD reached"); | ||
313 | TRACE_EXIT 0; /* EOD */ | ||
314 | default: | ||
315 | TRACE_ABORT(result, ft_t_noise, | ||
316 | "check_read_access() failed with result %d", | ||
317 | result); | ||
318 | TRACE_EXIT result; | ||
319 | } | ||
320 | while (req_len > 0) { | ||
321 | /* Allow escape from this loop on signal ! | ||
322 | */ | ||
323 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
324 | /* buf_len_rd == 0 means that we need to read a new | ||
325 | * segment. | ||
326 | */ | ||
327 | if (buf_len_rd == 0) { | ||
328 | while((result = zft_fetch_segment(zft_pos.seg_pos, | ||
329 | zft_deblock_buf, | ||
330 | FT_RD_AHEAD)) == 0) { | ||
331 | zft_pos.seg_pos ++; | ||
332 | zft_pos.seg_byte_pos = 0; | ||
333 | } | ||
334 | if (result < 0) { | ||
335 | zft_resid -= bytes_read; | ||
336 | TRACE_ABORT(result, ft_t_noise, | ||
337 | "zft_fetch_segment(): %d", | ||
338 | result); | ||
339 | } | ||
340 | seg_sz = result; | ||
341 | buf_len_rd = seg_sz - zft_pos.seg_byte_pos; | ||
342 | } | ||
343 | TRACE_CATCH(result = empty_deblock_buf(buff, | ||
344 | req_len, | ||
345 | zft_deblock_buf, | ||
346 | seg_sz, | ||
347 | &zft_pos, | ||
348 | volume), | ||
349 | zft_resid -= bytes_read); | ||
350 | TRACE(ft_t_data_flow, "bytes just read: %d", result); | ||
351 | bytes_read += result; /* what we got so far */ | ||
352 | buff += result; /* index in user-buffer */ | ||
353 | req_len -= result; /* what's left from req_len */ | ||
354 | } /* while (req_len > 0) */ | ||
355 | if (req_clipped) { | ||
356 | TRACE(ft_t_data_flow, | ||
357 | "maybe partial count because of eof mark"); | ||
358 | if (zft_just_before_eof && bytes_read == 0) { | ||
359 | /* req_len was > 0, but user didn't get | ||
360 | * anything the user has read in the eof-mark | ||
361 | */ | ||
362 | zft_move_past_eof(&zft_pos); | ||
363 | ftape_abort_operation(); | ||
364 | } else { | ||
365 | /* don't skip to the next file before the user | ||
366 | * tried to read a second time past EOF Just | ||
367 | * mark that we are at EOF and maybe decrement | ||
368 | * zft_seg_pos to stay in the same volume; | ||
369 | */ | ||
370 | zft_just_before_eof = 1; | ||
371 | zft_position_before_eof(&zft_pos, volume); | ||
372 | TRACE(ft_t_noise, "just before eof"); | ||
373 | } | ||
374 | } | ||
375 | zft_resid -= result; /* for MTSTATUS */ | ||
376 | TRACE_EXIT bytes_read; | ||
377 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-read.h b/drivers/char/ftape/zftape/zftape-read.h deleted file mode 100644 index 42941de0c23a..000000000000 --- a/drivers/char/ftape/zftape/zftape-read.h +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_READ_H | ||
2 | #define _ZFTAPE_READ_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/zftape/zftape-read.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:07 $ | ||
25 | * | ||
26 | * This file contains the definitions for the read functions | ||
27 | * for the zftape driver for Linux. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include "../lowlevel/ftape-read.h" | ||
32 | |||
33 | /* ftape-read.c defined global vars. | ||
34 | */ | ||
35 | extern int zft_just_before_eof; | ||
36 | |||
37 | /* ftape-read.c defined global functions. | ||
38 | */ | ||
39 | extern void zft_zap_read_buffers(void); | ||
40 | extern int zft_read_header_segments(void); | ||
41 | extern int zft_fetch_segment_fraction(const unsigned int segment, | ||
42 | void *buffer, | ||
43 | const ft_read_mode_t read_mode, | ||
44 | const unsigned int start, | ||
45 | const unsigned int size); | ||
46 | #define zft_fetch_segment(segment, address, read_mode) \ | ||
47 | zft_fetch_segment_fraction(segment, address, read_mode, \ | ||
48 | 0, FT_SEGMENT_SIZE) | ||
49 | /* hook for the VFS interface | ||
50 | */ | ||
51 | extern int _zft_read(char __user *buff, int req_len); | ||
52 | |||
53 | #endif /* _ZFTAPE_READ_H */ | ||
diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c deleted file mode 100644 index dab634686885..000000000000 --- a/drivers/char/ftape/zftape/zftape-rw.c +++ /dev/null | |||
@@ -1,375 +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/zftape/zftape-rw.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:19:08 $ | ||
22 | * | ||
23 | * This file contains some common code for the r/w code for | ||
24 | * zftape. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | |||
30 | #include <linux/zftape.h> | ||
31 | #include "../zftape/zftape-init.h" | ||
32 | #include "../zftape/zftape-eof.h" | ||
33 | #include "../zftape/zftape-ctl.h" | ||
34 | #include "../zftape/zftape-write.h" | ||
35 | #include "../zftape/zftape-read.h" | ||
36 | #include "../zftape/zftape-rw.h" | ||
37 | #include "../zftape/zftape-vtbl.h" | ||
38 | |||
39 | /* Global vars. | ||
40 | */ | ||
41 | |||
42 | __u8 *zft_deblock_buf; | ||
43 | __u8 *zft_hseg_buf; | ||
44 | int zft_deblock_segment = -1; | ||
45 | zft_status_enum zft_io_state = zft_idle; | ||
46 | int zft_header_changed; | ||
47 | int zft_qic113; /* conform to old specs. and old zftape */ | ||
48 | int zft_use_compression; | ||
49 | zft_position zft_pos = { | ||
50 | -1, /* seg_pos */ | ||
51 | 0, /* seg_byte_pos */ | ||
52 | 0, /* tape_pos */ | ||
53 | 0 /* volume_pos */ | ||
54 | }; | ||
55 | unsigned int zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; | ||
56 | __s64 zft_capacity; | ||
57 | |||
58 | unsigned int zft_written_segments; | ||
59 | int zft_label_changed; | ||
60 | |||
61 | /* Local vars. | ||
62 | */ | ||
63 | |||
64 | unsigned int zft_get_seg_sz(unsigned int segment) | ||
65 | { | ||
66 | int size; | ||
67 | TRACE_FUN(ft_t_any); | ||
68 | |||
69 | size = FT_SEGMENT_SIZE - | ||
70 | count_ones(ftape_get_bad_sector_entry(segment))*FT_SECTOR_SIZE; | ||
71 | if (size > 0) { | ||
72 | TRACE_EXIT (unsigned)size; | ||
73 | } else { | ||
74 | TRACE_EXIT 0; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | /* ftape_set_flags(). Claus-Justus Heine, 1994/1995 | ||
79 | */ | ||
80 | void zft_set_flags(unsigned minor_unit) | ||
81 | { | ||
82 | TRACE_FUN(ft_t_flow); | ||
83 | |||
84 | zft_use_compression = zft_qic_mode = 0; | ||
85 | switch (minor_unit & ZFT_MINOR_OP_MASK) { | ||
86 | case (ZFT_Q80_MODE | ZFT_ZIP_MODE): | ||
87 | case ZFT_ZIP_MODE: | ||
88 | zft_use_compression = 1; | ||
89 | case 0: | ||
90 | case ZFT_Q80_MODE: | ||
91 | zft_qic_mode = 1; | ||
92 | if (zft_mt_compression) { /* override the default */ | ||
93 | zft_use_compression = 1; | ||
94 | } | ||
95 | break; | ||
96 | case ZFT_RAW_MODE: | ||
97 | TRACE(ft_t_noise, "switching to raw mode"); | ||
98 | break; | ||
99 | default: | ||
100 | TRACE(ft_t_warn, "Warning:\n" | ||
101 | KERN_INFO "Wrong combination of minor device bits.\n" | ||
102 | KERN_INFO "Switching to raw read-only mode."); | ||
103 | zft_write_protected = 1; | ||
104 | break; | ||
105 | } | ||
106 | TRACE_EXIT; | ||
107 | } | ||
108 | |||
109 | /* computes the segment and byte offset inside the segment | ||
110 | * corresponding to tape_pos. | ||
111 | * | ||
112 | * tape_pos gives the offset in bytes from the beginning of the | ||
113 | * ft_first_data_segment *seg_byte_pos is the offset in the current | ||
114 | * segment in bytes | ||
115 | * | ||
116 | * Of, if this routine was called often one should cache the last data | ||
117 | * pos it was called with, but actually this is only needed in | ||
118 | * ftape_seek_block(), that is, almost never. | ||
119 | */ | ||
120 | int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos) | ||
121 | { | ||
122 | int segment; | ||
123 | int seg_sz; | ||
124 | TRACE_FUN(ft_t_flow); | ||
125 | |||
126 | if (tape_pos == 0) { | ||
127 | *seg_byte_pos = 0; | ||
128 | segment = ft_first_data_segment; | ||
129 | } else { | ||
130 | seg_sz = 0; | ||
131 | |||
132 | for (segment = ft_first_data_segment; | ||
133 | ((tape_pos > 0) && (segment <= ft_last_data_segment)); | ||
134 | segment++) { | ||
135 | seg_sz = zft_get_seg_sz(segment); | ||
136 | tape_pos -= seg_sz; | ||
137 | } | ||
138 | if(tape_pos >= 0) { | ||
139 | /* the case tape_pos > != 0 means that the | ||
140 | * argument tape_pos lies beyond the EOT. | ||
141 | */ | ||
142 | *seg_byte_pos= 0; | ||
143 | } else { /* tape_pos < 0 */ | ||
144 | segment--; | ||
145 | *seg_byte_pos= tape_pos + seg_sz; | ||
146 | } | ||
147 | } | ||
148 | TRACE_EXIT(segment); | ||
149 | } | ||
150 | |||
151 | /* ftape_calc_tape_pos(). | ||
152 | * | ||
153 | * computes the offset in bytes from the beginning of the | ||
154 | * ft_first_data_segment inverse to ftape_calc_seg_byte_coord | ||
155 | * | ||
156 | * We should do some caching. But how: | ||
157 | * | ||
158 | * Each time the header segments are read in, this routine is called | ||
159 | * with ft_tracks_per_tape*segments_per_track argumnet. So this should be | ||
160 | * the time to reset the cache. | ||
161 | * | ||
162 | * Also, it might be in the future that the bad sector map gets | ||
163 | * changed. -> reset the cache | ||
164 | */ | ||
165 | static int seg_pos; | ||
166 | static __s64 tape_pos; | ||
167 | |||
168 | __s64 zft_get_capacity(void) | ||
169 | { | ||
170 | seg_pos = ft_first_data_segment; | ||
171 | tape_pos = 0; | ||
172 | |||
173 | while (seg_pos <= ft_last_data_segment) { | ||
174 | tape_pos += zft_get_seg_sz(seg_pos ++); | ||
175 | } | ||
176 | return tape_pos; | ||
177 | } | ||
178 | |||
179 | __s64 zft_calc_tape_pos(int segment) | ||
180 | { | ||
181 | int d1, d2, d3; | ||
182 | TRACE_FUN(ft_t_any); | ||
183 | |||
184 | if (segment > ft_last_data_segment) { | ||
185 | TRACE_EXIT zft_capacity; | ||
186 | } | ||
187 | if (segment < ft_first_data_segment) { | ||
188 | TRACE_EXIT 0; | ||
189 | } | ||
190 | d2 = segment - seg_pos; | ||
191 | if (-d2 > 10) { | ||
192 | d1 = segment - ft_first_data_segment; | ||
193 | if (-d2 > d1) { | ||
194 | tape_pos = 0; | ||
195 | seg_pos = ft_first_data_segment; | ||
196 | d2 = d1; | ||
197 | } | ||
198 | } | ||
199 | if (d2 > 10) { | ||
200 | d3 = ft_last_data_segment - segment; | ||
201 | if (d2 > d3) { | ||
202 | tape_pos = zft_capacity; | ||
203 | seg_pos = ft_last_data_segment + 1; | ||
204 | d2 = -d3; | ||
205 | } | ||
206 | } | ||
207 | if (d2 > 0) { | ||
208 | while (seg_pos < segment) { | ||
209 | tape_pos += zft_get_seg_sz(seg_pos++); | ||
210 | } | ||
211 | } else { | ||
212 | while (seg_pos > segment) { | ||
213 | tape_pos -= zft_get_seg_sz(--seg_pos); | ||
214 | } | ||
215 | } | ||
216 | TRACE(ft_t_noise, "new cached pos: %d", seg_pos); | ||
217 | |||
218 | TRACE_EXIT tape_pos; | ||
219 | } | ||
220 | |||
221 | /* copy Z-label string to buffer, keeps track of the correct offset in | ||
222 | * `buffer' | ||
223 | */ | ||
224 | void zft_update_label(__u8 *buffer) | ||
225 | { | ||
226 | TRACE_FUN(ft_t_flow); | ||
227 | |||
228 | if (strncmp(&buffer[FT_LABEL], ZFTAPE_LABEL, | ||
229 | sizeof(ZFTAPE_LABEL)-1) != 0) { | ||
230 | TRACE(ft_t_info, "updating label from \"%s\" to \"%s\"", | ||
231 | &buffer[FT_LABEL], ZFTAPE_LABEL); | ||
232 | strcpy(&buffer[FT_LABEL], ZFTAPE_LABEL); | ||
233 | memset(&buffer[FT_LABEL] + sizeof(ZFTAPE_LABEL) - 1, ' ', | ||
234 | FT_LABEL_SZ - sizeof(ZFTAPE_LABEL + 1)); | ||
235 | PUT4(buffer, FT_LABEL_DATE, 0); | ||
236 | zft_label_changed = zft_header_changed = 1; /* changed */ | ||
237 | } | ||
238 | TRACE_EXIT; | ||
239 | } | ||
240 | |||
241 | int zft_verify_write_segments(unsigned int segment, | ||
242 | __u8 *data, size_t size, | ||
243 | __u8 *buffer) | ||
244 | { | ||
245 | int result; | ||
246 | __u8 *write_buf; | ||
247 | __u8 *src_buf; | ||
248 | int single; | ||
249 | int seg_pos; | ||
250 | int seg_sz; | ||
251 | int remaining; | ||
252 | ft_write_mode_t write_mode; | ||
253 | TRACE_FUN(ft_t_flow); | ||
254 | |||
255 | seg_pos = segment; | ||
256 | seg_sz = zft_get_seg_sz(seg_pos); | ||
257 | src_buf = data; | ||
258 | single = size <= seg_sz; | ||
259 | remaining = size; | ||
260 | do { | ||
261 | TRACE(ft_t_noise, "\n" | ||
262 | KERN_INFO "remaining: %d\n" | ||
263 | KERN_INFO "seg_sz : %d\n" | ||
264 | KERN_INFO "segment : %d", | ||
265 | remaining, seg_sz, seg_pos); | ||
266 | if (remaining == seg_sz) { | ||
267 | write_buf = src_buf; | ||
268 | write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI; | ||
269 | remaining = 0; | ||
270 | } else if (remaining > seg_sz) { | ||
271 | write_buf = src_buf; | ||
272 | write_mode = FT_WR_ASYNC; /* don't start tape */ | ||
273 | remaining -= seg_sz; | ||
274 | } else { /* remaining < seg_sz */ | ||
275 | write_buf = buffer; | ||
276 | memcpy(write_buf, src_buf, remaining); | ||
277 | memset(&write_buf[remaining],'\0',seg_sz-remaining); | ||
278 | write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI; | ||
279 | remaining = 0; | ||
280 | } | ||
281 | if ((result = ftape_write_segment(seg_pos, | ||
282 | write_buf, | ||
283 | write_mode)) != seg_sz) { | ||
284 | TRACE(ft_t_err, "Error: " | ||
285 | "Couldn't write segment %d", seg_pos); | ||
286 | TRACE_EXIT result < 0 ? result : -EIO; /* bail out */ | ||
287 | } | ||
288 | zft_written_segments ++; | ||
289 | seg_sz = zft_get_seg_sz(++seg_pos); | ||
290 | src_buf += result; | ||
291 | } while (remaining > 0); | ||
292 | if (ftape_get_status()->fti_state == writing) { | ||
293 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
294 | TRACE_CATCH(ftape_abort_operation(),); | ||
295 | zft_prevent_flush(); | ||
296 | } | ||
297 | seg_pos = segment; | ||
298 | src_buf = data; | ||
299 | remaining = size; | ||
300 | do { | ||
301 | TRACE_CATCH(result = ftape_read_segment(seg_pos, buffer, | ||
302 | single ? FT_RD_SINGLE | ||
303 | : FT_RD_AHEAD),); | ||
304 | if (memcmp(src_buf, buffer, | ||
305 | remaining > result ? result : remaining) != 0) { | ||
306 | TRACE_ABORT(-EIO, ft_t_err, | ||
307 | "Failed to verify written segment %d", | ||
308 | seg_pos); | ||
309 | } | ||
310 | remaining -= result; | ||
311 | TRACE(ft_t_noise, "verify successful:\n" | ||
312 | KERN_INFO "segment : %d\n" | ||
313 | KERN_INFO "segsize : %d\n" | ||
314 | KERN_INFO "remaining: %d", | ||
315 | seg_pos, result, remaining); | ||
316 | src_buf += seg_sz; | ||
317 | seg_pos++; | ||
318 | } while (remaining > 0); | ||
319 | TRACE_EXIT size; | ||
320 | } | ||
321 | |||
322 | |||
323 | /* zft_erase(). implemented compression-handling | ||
324 | * | ||
325 | * calculate the first data-segment when using/not using compression. | ||
326 | * | ||
327 | * update header-segment and compression-map-segment. | ||
328 | */ | ||
329 | int zft_erase(void) | ||
330 | { | ||
331 | int result = 0; | ||
332 | TRACE_FUN(ft_t_flow); | ||
333 | |||
334 | if (!zft_header_read) { | ||
335 | TRACE_CATCH(zft_vmalloc_once((void **)&zft_hseg_buf, | ||
336 | FT_SEGMENT_SIZE),); | ||
337 | /* no need to read the vtbl and compression map */ | ||
338 | TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),); | ||
339 | if ((zft_old_ftape = | ||
340 | zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]))) { | ||
341 | zft_ftape_extract_file_marks(zft_hseg_buf); | ||
342 | } | ||
343 | TRACE(ft_t_noise, | ||
344 | "ft_first_data_segment: %d, ft_last_data_segment: %d", | ||
345 | ft_first_data_segment, ft_last_data_segment); | ||
346 | zft_qic113 = (ft_format_code != fmt_normal && | ||
347 | ft_format_code != fmt_1100ft && | ||
348 | ft_format_code != fmt_425ft); | ||
349 | } | ||
350 | if (zft_old_ftape) { | ||
351 | zft_clear_ftape_file_marks(); | ||
352 | zft_old_ftape = 0; /* no longer old ftape */ | ||
353 | } | ||
354 | PUT2(zft_hseg_buf, FT_CMAP_START, 0); | ||
355 | zft_volume_table_changed = 1; | ||
356 | zft_capacity = zft_get_capacity(); | ||
357 | zft_init_vtbl(); | ||
358 | /* the rest must be done in ftape_update_header_segments | ||
359 | */ | ||
360 | zft_header_read = 1; | ||
361 | zft_header_changed = 1; /* force update of timestamp */ | ||
362 | result = zft_update_header_segments(); | ||
363 | |||
364 | ftape_abort_operation(); | ||
365 | |||
366 | zft_reset_position(&zft_pos); | ||
367 | zft_set_flags (zft_unit); | ||
368 | TRACE_EXIT result; | ||
369 | } | ||
370 | |||
371 | unsigned int zft_get_time(void) | ||
372 | { | ||
373 | unsigned int date = FT_TIME_STAMP(2097, 11, 30, 23, 59, 59); /* fun */ | ||
374 | return date; | ||
375 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-rw.h b/drivers/char/ftape/zftape/zftape-rw.h deleted file mode 100644 index 1ceec22b60bd..000000000000 --- a/drivers/char/ftape/zftape/zftape-rw.h +++ /dev/null | |||
@@ -1,101 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_RW_H | ||
2 | #define _ZFTAPE_RW_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/zftape/zftape-rw.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:09 $ | ||
25 | * | ||
26 | * This file contains the definitions for the read and write | ||
27 | * functions for the QIC-117 floppy-tape driver for Linux. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include "../zftape/zftape-buffers.h" | ||
32 | |||
33 | #define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape) | ||
34 | |||
35 | /* QIC-113 Rev. G says that `a maximum of 63488 raw bytes may be | ||
36 | * compressed into a single frame'. | ||
37 | * Maybe we should stick to 32kb to make it more `beautiful' | ||
38 | */ | ||
39 | #define ZFT_MAX_BLK_SZ (62*1024) /* bytes */ | ||
40 | #if !defined(CONFIG_ZFT_DFLT_BLK_SZ) | ||
41 | # define CONFIG_ZFT_DFLT_BLK_SZ (10*1024) /* bytes, default of gnu tar */ | ||
42 | #elif CONFIG_ZFT_DFLT_BLK_SZ == 0 | ||
43 | # undef CONFIG_ZFT_DFLT_BLK_SZ | ||
44 | # define CONFIG_ZFT_DFLT_BLK_SZ 1 | ||
45 | #elif (CONFIG_ZFT_DFLT_BLK_SZ % 1024) != 0 | ||
46 | # error CONFIG_ZFT_DFLT_BLK_SZ must be 1 or a multiple of 1024 | ||
47 | #endif | ||
48 | /* The *optional* compression routines need some overhead per tape | ||
49 | * block for their purposes. Instead of asking the actual compression | ||
50 | * implementation how much it needs, we restrict this overhead to be | ||
51 | * maximal of ZFT_CMPT_OVERHEAD size. We need this for EOT | ||
52 | * conditions. The tape is assumed to be logical at EOT when the | ||
53 | * distance from the physical EOT is less than | ||
54 | * one tape block + ZFT_CMPR_OVERHEAD | ||
55 | */ | ||
56 | #define ZFT_CMPR_OVERHEAD 16 /* bytes */ | ||
57 | |||
58 | typedef enum | ||
59 | { | ||
60 | zft_idle = 0, | ||
61 | zft_reading, | ||
62 | zft_writing, | ||
63 | } zft_status_enum; | ||
64 | |||
65 | typedef struct /* all values measured in bytes */ | ||
66 | { | ||
67 | int seg_pos; /* segment currently positioned at */ | ||
68 | int seg_byte_pos; /* offset in current segment */ | ||
69 | __s64 tape_pos; /* real offset from BOT */ | ||
70 | __s64 volume_pos; /* pos. in uncompressed data stream in | ||
71 | * current volume | ||
72 | */ | ||
73 | } zft_position; | ||
74 | |||
75 | extern zft_position zft_pos; | ||
76 | extern __u8 *zft_deblock_buf; | ||
77 | extern __u8 *zft_hseg_buf; | ||
78 | extern int zft_deblock_segment; | ||
79 | extern zft_status_enum zft_io_state; | ||
80 | extern int zft_header_changed; | ||
81 | extern int zft_qic113; /* conform to old specs. and old zftape */ | ||
82 | extern int zft_use_compression; | ||
83 | extern unsigned int zft_blk_sz; | ||
84 | extern __s64 zft_capacity; | ||
85 | extern unsigned int zft_written_segments; | ||
86 | extern int zft_label_changed; | ||
87 | |||
88 | /* zftape-rw.c exported functions | ||
89 | */ | ||
90 | extern unsigned int zft_get_seg_sz(unsigned int segment); | ||
91 | extern void zft_set_flags(unsigned int minor_unit); | ||
92 | extern int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos); | ||
93 | extern __s64 zft_calc_tape_pos(int segment); | ||
94 | extern __s64 zft_get_capacity(void); | ||
95 | extern void zft_update_label(__u8 *buffer); | ||
96 | extern int zft_erase(void); | ||
97 | extern int zft_verify_write_segments(unsigned int segment, | ||
98 | __u8 *data, size_t size, __u8 *buffer); | ||
99 | extern unsigned int zft_get_time(void); | ||
100 | #endif /* _ZFTAPE_RW_H */ | ||
101 | |||
diff --git a/drivers/char/ftape/zftape/zftape-vtbl.c b/drivers/char/ftape/zftape/zftape-vtbl.c deleted file mode 100644 index ad7f8be6340b..000000000000 --- a/drivers/char/ftape/zftape/zftape-vtbl.c +++ /dev/null | |||
@@ -1,757 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1995-1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU General Public License as | ||
6 | published by the Free Software Foundation; either version 2, or (at | ||
7 | your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, but | ||
10 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | 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, | ||
17 | USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.c,v $ | ||
21 | * $Revision: 1.7.6.1 $ | ||
22 | * $Date: 1997/11/24 13:48:31 $ | ||
23 | * | ||
24 | * This file defines a volume table as defined in various QIC | ||
25 | * standards. | ||
26 | * | ||
27 | * This is a minimal implementation, just allowing ordinary DOS | ||
28 | * :( prgrams to identify the cartridge as used. | ||
29 | */ | ||
30 | |||
31 | #include <linux/errno.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/slab.h> | ||
34 | |||
35 | #include <linux/zftape.h> | ||
36 | #include "../zftape/zftape-init.h" | ||
37 | #include "../zftape/zftape-eof.h" | ||
38 | #include "../zftape/zftape-ctl.h" | ||
39 | #include "../zftape/zftape-write.h" | ||
40 | #include "../zftape/zftape-read.h" | ||
41 | #include "../zftape/zftape-rw.h" | ||
42 | #include "../zftape/zftape-vtbl.h" | ||
43 | |||
44 | #define ZFT_CMAP_HACK /* leave this defined to hide the compression map */ | ||
45 | |||
46 | /* | ||
47 | * global variables | ||
48 | */ | ||
49 | int zft_qic_mode = 1; /* use the vtbl */ | ||
50 | int zft_old_ftape; /* prevents old ftaped tapes to be overwritten */ | ||
51 | int zft_volume_table_changed; /* for write_header_segments() */ | ||
52 | |||
53 | /* | ||
54 | * private variables (only exported for inline functions) | ||
55 | */ | ||
56 | LIST_HEAD(zft_vtbl); | ||
57 | |||
58 | /* We could also allocate these dynamically when extracting the volume table | ||
59 | * sizeof(zft_volinfo) is about 32 or something close to that | ||
60 | */ | ||
61 | static zft_volinfo tape_vtbl; | ||
62 | static zft_volinfo eot_vtbl; | ||
63 | static zft_volinfo *cur_vtbl; | ||
64 | |||
65 | static inline void zft_new_vtbl_entry(void) | ||
66 | { | ||
67 | struct list_head *tmp = &zft_last_vtbl->node; | ||
68 | zft_volinfo *new = zft_kmalloc(sizeof(zft_volinfo)); | ||
69 | |||
70 | list_add(&new->node, tmp); | ||
71 | new->count = zft_eom_vtbl->count ++; | ||
72 | } | ||
73 | |||
74 | void zft_free_vtbl(void) | ||
75 | { | ||
76 | for (;;) { | ||
77 | struct list_head *tmp = zft_vtbl.prev; | ||
78 | zft_volinfo *vtbl; | ||
79 | |||
80 | if (tmp == &zft_vtbl) | ||
81 | break; | ||
82 | list_del(tmp); | ||
83 | vtbl = list_entry(tmp, zft_volinfo, node); | ||
84 | zft_kfree(vtbl, sizeof(zft_volinfo)); | ||
85 | } | ||
86 | INIT_LIST_HEAD(&zft_vtbl); | ||
87 | cur_vtbl = NULL; | ||
88 | } | ||
89 | |||
90 | /* initialize vtbl, called by ftape_new_cartridge() | ||
91 | */ | ||
92 | void zft_init_vtbl(void) | ||
93 | { | ||
94 | zft_volinfo *new; | ||
95 | |||
96 | zft_free_vtbl(); | ||
97 | |||
98 | /* Create the two dummy vtbl entries | ||
99 | */ | ||
100 | new = zft_kmalloc(sizeof(zft_volinfo)); | ||
101 | list_add(&new->node, &zft_vtbl); | ||
102 | new = zft_kmalloc(sizeof(zft_volinfo)); | ||
103 | list_add(&new->node, &zft_vtbl); | ||
104 | zft_head_vtbl->end_seg = ft_first_data_segment; | ||
105 | zft_head_vtbl->blk_sz = zft_blk_sz; | ||
106 | zft_head_vtbl->count = -1; | ||
107 | zft_eom_vtbl->start_seg = ft_first_data_segment + 1; | ||
108 | zft_eom_vtbl->end_seg = ft_last_data_segment + 1; | ||
109 | zft_eom_vtbl->blk_sz = zft_blk_sz; | ||
110 | zft_eom_vtbl->count = 0; | ||
111 | |||
112 | /* Reset the pointer for zft_find_volume() | ||
113 | */ | ||
114 | cur_vtbl = zft_eom_vtbl; | ||
115 | |||
116 | /* initialize the dummy vtbl entries for zft_qic_mode == 0 | ||
117 | */ | ||
118 | eot_vtbl.start_seg = ft_last_data_segment + 1; | ||
119 | eot_vtbl.end_seg = ft_last_data_segment + 1; | ||
120 | eot_vtbl.blk_sz = zft_blk_sz; | ||
121 | eot_vtbl.count = -1; | ||
122 | tape_vtbl.start_seg = ft_first_data_segment; | ||
123 | tape_vtbl.end_seg = ft_last_data_segment; | ||
124 | tape_vtbl.blk_sz = zft_blk_sz; | ||
125 | tape_vtbl.size = zft_capacity; | ||
126 | tape_vtbl.count = 0; | ||
127 | } | ||
128 | |||
129 | /* check for a valid VTBL signature. | ||
130 | */ | ||
131 | static int vtbl_signature_valid(__u8 signature[4]) | ||
132 | { | ||
133 | const char *vtbl_ids[] = VTBL_IDS; /* valid signatures */ | ||
134 | int j; | ||
135 | |||
136 | for (j = 0; | ||
137 | (j < NR_ITEMS(vtbl_ids)) && (memcmp(signature, vtbl_ids[j], 4) != 0); | ||
138 | j++); | ||
139 | return j < NR_ITEMS(vtbl_ids); | ||
140 | } | ||
141 | |||
142 | /* We used to store the block-size of the volume in the volume-label, | ||
143 | * using the keyword "blocksize". The blocksize written to the | ||
144 | * volume-label is in bytes. | ||
145 | * | ||
146 | * We use this now only for compatibility with old zftape version. We | ||
147 | * store the blocksize directly as binary number in the vendor | ||
148 | * extension part of the volume entry. | ||
149 | */ | ||
150 | static int check_volume_label(const char *label, int *blk_sz) | ||
151 | { | ||
152 | int valid_format; | ||
153 | char *blocksize; | ||
154 | TRACE_FUN(ft_t_flow); | ||
155 | |||
156 | TRACE(ft_t_noise, "called with \"%s\" / \"%s\"", label, ZFT_VOL_NAME); | ||
157 | if (strncmp(label, ZFT_VOL_NAME, strlen(ZFT_VOL_NAME)) != 0) { | ||
158 | *blk_sz = 1; /* smallest block size that we allow */ | ||
159 | valid_format = 0; | ||
160 | } else { | ||
161 | TRACE(ft_t_noise, "got old style zftape vtbl entry"); | ||
162 | /* get the default blocksize */ | ||
163 | /* use the kernel strstr() */ | ||
164 | blocksize= strstr(label, " blocksize "); | ||
165 | if (blocksize) { | ||
166 | blocksize += strlen(" blocksize "); | ||
167 | for(*blk_sz= 0; | ||
168 | *blocksize >= '0' && *blocksize <= '9'; | ||
169 | blocksize++) { | ||
170 | *blk_sz *= 10; | ||
171 | *blk_sz += *blocksize - '0'; | ||
172 | } | ||
173 | if (*blk_sz > ZFT_MAX_BLK_SZ) { | ||
174 | *blk_sz= 1; | ||
175 | valid_format= 0; | ||
176 | } else { | ||
177 | valid_format = 1; | ||
178 | } | ||
179 | } else { | ||
180 | *blk_sz= 1; | ||
181 | valid_format= 0; | ||
182 | } | ||
183 | } | ||
184 | TRACE_EXIT valid_format; | ||
185 | } | ||
186 | |||
187 | /* check for a zftape volume | ||
188 | */ | ||
189 | static int check_volume(__u8 *entry, zft_volinfo *volume) | ||
190 | { | ||
191 | TRACE_FUN(ft_t_flow); | ||
192 | |||
193 | if(strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, | ||
194 | strlen(ZFTAPE_SIG)) == 0) { | ||
195 | TRACE(ft_t_noise, "got new style zftape vtbl entry"); | ||
196 | volume->blk_sz = GET2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ); | ||
197 | volume->qic113 = entry[VTBL_EXT+EXT_ZFTAPE_QIC113]; | ||
198 | TRACE_EXIT 1; | ||
199 | } else { | ||
200 | TRACE_EXIT check_volume_label(&entry[VTBL_DESC], &volume->blk_sz); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | |||
205 | /* create zftape specific vtbl entry, the volume bounds are inserted | ||
206 | * in the calling function, zft_create_volume_headers() | ||
207 | */ | ||
208 | static void create_zft_volume(__u8 *entry, zft_volinfo *vtbl) | ||
209 | { | ||
210 | TRACE_FUN(ft_t_flow); | ||
211 | |||
212 | memset(entry, 0, VTBL_SIZE); | ||
213 | memcpy(&entry[VTBL_SIG], VTBL_ID, 4); | ||
214 | sprintf(&entry[VTBL_DESC], ZFT_VOL_NAME" %03d", vtbl->count); | ||
215 | entry[VTBL_FLAGS] = (VTBL_FL_NOT_VERIFIED | VTBL_FL_SEG_SPANNING); | ||
216 | entry[VTBL_M_NO] = 1; /* multi_cartridge_count */ | ||
217 | strcpy(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG); | ||
218 | PUT2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ, vtbl->blk_sz); | ||
219 | if (zft_qic113) { | ||
220 | PUT8(entry, VTBL_DATA_SIZE, vtbl->size); | ||
221 | entry[VTBL_CMPR] = VTBL_CMPR_UNREG; | ||
222 | if (vtbl->use_compression) { /* use compression: */ | ||
223 | entry[VTBL_CMPR] |= VTBL_CMPR_USED; | ||
224 | } | ||
225 | entry[VTBL_EXT+EXT_ZFTAPE_QIC113] = 1; | ||
226 | } else { | ||
227 | PUT4(entry, VTBL_DATA_SIZE, vtbl->size); | ||
228 | entry[VTBL_K_CMPR] = VTBL_CMPR_UNREG; | ||
229 | if (vtbl->use_compression) { /* use compression: */ | ||
230 | entry[VTBL_K_CMPR] |= VTBL_CMPR_USED; | ||
231 | } | ||
232 | } | ||
233 | if (ft_format_code == fmt_big) { | ||
234 | /* SCSI like vtbl, store the number of used | ||
235 | * segments as 4 byte value | ||
236 | */ | ||
237 | PUT4(entry, VTBL_SCSI_SEGS, vtbl->end_seg-vtbl->start_seg + 1); | ||
238 | } else { | ||
239 | /* normal, QIC-80MC like vtbl | ||
240 | */ | ||
241 | PUT2(entry, VTBL_START, vtbl->start_seg); | ||
242 | PUT2(entry, VTBL_END, vtbl->end_seg); | ||
243 | } | ||
244 | TRACE_EXIT; | ||
245 | } | ||
246 | |||
247 | /* this one creates the volume headers for each volume. It is assumed | ||
248 | * that buffer already contains the old volume-table, so that vtbl | ||
249 | * entries without the zft_volume flag set can savely be ignored. | ||
250 | */ | ||
251 | static void zft_create_volume_headers(__u8 *buffer) | ||
252 | { | ||
253 | __u8 *entry; | ||
254 | struct list_head *tmp; | ||
255 | zft_volinfo *vtbl; | ||
256 | TRACE_FUN(ft_t_flow); | ||
257 | |||
258 | #ifdef ZFT_CMAP_HACK | ||
259 | if((strncmp(&buffer[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, | ||
260 | strlen(ZFTAPE_SIG)) == 0) && | ||
261 | buffer[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { | ||
262 | TRACE(ft_t_noise, "deleting cmap volume"); | ||
263 | memmove(buffer, buffer + VTBL_SIZE, | ||
264 | FT_SEGMENT_SIZE - VTBL_SIZE); | ||
265 | } | ||
266 | #endif | ||
267 | entry = buffer; | ||
268 | for (tmp = zft_head_vtbl->node.next; | ||
269 | tmp != &zft_eom_vtbl->node; | ||
270 | tmp = tmp->next) { | ||
271 | vtbl = list_entry(tmp, zft_volinfo, node); | ||
272 | /* we now fill in the values only for newly created volumes. | ||
273 | */ | ||
274 | if (vtbl->new_volume) { | ||
275 | create_zft_volume(entry, vtbl); | ||
276 | vtbl->new_volume = 0; /* clear the flag */ | ||
277 | } | ||
278 | |||
279 | DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], vtbl); | ||
280 | entry += VTBL_SIZE; | ||
281 | } | ||
282 | memset(entry, 0, FT_SEGMENT_SIZE - zft_eom_vtbl->count * VTBL_SIZE); | ||
283 | TRACE_EXIT; | ||
284 | } | ||
285 | |||
286 | /* write volume table to tape. Calls zft_create_volume_headers() | ||
287 | */ | ||
288 | int zft_update_volume_table(unsigned int segment) | ||
289 | { | ||
290 | int result = 0; | ||
291 | __u8 *verify_buf = NULL; | ||
292 | TRACE_FUN(ft_t_flow); | ||
293 | |||
294 | TRACE_CATCH(result = ftape_read_segment(ft_first_data_segment, | ||
295 | zft_deblock_buf, | ||
296 | FT_RD_SINGLE),); | ||
297 | zft_create_volume_headers(zft_deblock_buf); | ||
298 | TRACE(ft_t_noise, "writing volume table segment %d", segment); | ||
299 | if (zft_vmalloc_once(&verify_buf, FT_SEGMENT_SIZE) == 0) { | ||
300 | TRACE_CATCH(zft_verify_write_segments(segment, | ||
301 | zft_deblock_buf, result, | ||
302 | verify_buf), | ||
303 | zft_vfree(&verify_buf, FT_SEGMENT_SIZE)); | ||
304 | zft_vfree(&verify_buf, FT_SEGMENT_SIZE); | ||
305 | } else { | ||
306 | TRACE_CATCH(ftape_write_segment(segment, zft_deblock_buf, | ||
307 | FT_WR_SINGLE),); | ||
308 | } | ||
309 | TRACE_EXIT 0; | ||
310 | } | ||
311 | |||
312 | /* non zftape volumes are handled in raw mode. Thus we need to | ||
313 | * calculate the raw amount of data contained in those segments. | ||
314 | */ | ||
315 | static void extract_alien_volume(__u8 *entry, zft_volinfo *vtbl) | ||
316 | { | ||
317 | TRACE_FUN(ft_t_flow); | ||
318 | |||
319 | vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) - | ||
320 | zft_calc_tape_pos(zft_last_vtbl->start_seg)); | ||
321 | vtbl->use_compression = 0; | ||
322 | vtbl->qic113 = zft_qic113; | ||
323 | if (vtbl->qic113) { | ||
324 | TRACE(ft_t_noise, | ||
325 | "Fake alien volume's size from " LL_X " to " LL_X, | ||
326 | LL(GET8(entry, VTBL_DATA_SIZE)), LL(vtbl->size)); | ||
327 | } else { | ||
328 | TRACE(ft_t_noise, | ||
329 | "Fake alien volume's size from %d to " LL_X, | ||
330 | (int)GET4(entry, VTBL_DATA_SIZE), LL(vtbl->size)); | ||
331 | } | ||
332 | TRACE_EXIT; | ||
333 | } | ||
334 | |||
335 | |||
336 | /* extract an zftape specific volume | ||
337 | */ | ||
338 | static void extract_zft_volume(__u8 *entry, zft_volinfo *vtbl) | ||
339 | { | ||
340 | TRACE_FUN(ft_t_flow); | ||
341 | |||
342 | if (vtbl->qic113) { | ||
343 | vtbl->size = GET8(entry, VTBL_DATA_SIZE); | ||
344 | vtbl->use_compression = | ||
345 | (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; | ||
346 | } else { | ||
347 | vtbl->size = GET4(entry, VTBL_DATA_SIZE); | ||
348 | if (entry[VTBL_K_CMPR] & VTBL_CMPR_UNREG) { | ||
349 | vtbl->use_compression = | ||
350 | (entry[VTBL_K_CMPR] & VTBL_CMPR_USED) != 0; | ||
351 | } else if (entry[VTBL_CMPR] & VTBL_CMPR_UNREG) { | ||
352 | vtbl->use_compression = | ||
353 | (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; | ||
354 | } else { | ||
355 | TRACE(ft_t_warn, "Geeh! There is something wrong:\n" | ||
356 | KERN_INFO "QIC compression (Rev = K): %x\n" | ||
357 | KERN_INFO "QIC compression (Rev > K): %x", | ||
358 | entry[VTBL_K_CMPR], entry[VTBL_CMPR]); | ||
359 | } | ||
360 | } | ||
361 | TRACE_EXIT; | ||
362 | } | ||
363 | |||
364 | /* extract the volume table from buffer. "buffer" must already contain | ||
365 | * the vtbl-segment | ||
366 | */ | ||
367 | int zft_extract_volume_headers(__u8 *buffer) | ||
368 | { | ||
369 | __u8 *entry; | ||
370 | TRACE_FUN(ft_t_flow); | ||
371 | |||
372 | zft_init_vtbl(); | ||
373 | entry = buffer; | ||
374 | #ifdef ZFT_CMAP_HACK | ||
375 | if ((strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, | ||
376 | strlen(ZFTAPE_SIG)) == 0) && | ||
377 | entry[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { | ||
378 | TRACE(ft_t_noise, "ignoring cmap volume"); | ||
379 | entry += VTBL_SIZE; | ||
380 | } | ||
381 | #endif | ||
382 | /* the end of the vtbl is indicated by an invalid signature | ||
383 | */ | ||
384 | while (vtbl_signature_valid(&entry[VTBL_SIG]) && | ||
385 | (entry - buffer) < FT_SEGMENT_SIZE) { | ||
386 | zft_new_vtbl_entry(); | ||
387 | if (ft_format_code == fmt_big) { | ||
388 | /* SCSI like vtbl, stores only the number of | ||
389 | * segments used | ||
390 | */ | ||
391 | unsigned int num_segments= GET4(entry, VTBL_SCSI_SEGS); | ||
392 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
393 | zft_last_vtbl->end_seg = | ||
394 | zft_last_vtbl->start_seg + num_segments - 1; | ||
395 | } else { | ||
396 | /* `normal', QIC-80 like vtbl | ||
397 | */ | ||
398 | zft_last_vtbl->start_seg = GET2(entry, VTBL_START); | ||
399 | zft_last_vtbl->end_seg = GET2(entry, VTBL_END); | ||
400 | } | ||
401 | zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1; | ||
402 | /* check if we created this volume and get the | ||
403 | * blk_sz | ||
404 | */ | ||
405 | zft_last_vtbl->zft_volume = check_volume(entry, zft_last_vtbl); | ||
406 | if (zft_last_vtbl->zft_volume == 0) { | ||
407 | extract_alien_volume(entry, zft_last_vtbl); | ||
408 | } else { | ||
409 | extract_zft_volume(entry, zft_last_vtbl); | ||
410 | } | ||
411 | DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], zft_last_vtbl); | ||
412 | entry +=VTBL_SIZE; | ||
413 | } | ||
414 | #if 0 | ||
415 | /* | ||
416 | * undefine to test end of tape handling | ||
417 | */ | ||
418 | zft_new_vtbl_entry(); | ||
419 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
420 | zft_last_vtbl->end_seg = ft_last_data_segment - 10; | ||
421 | zft_last_vtbl->blk_sz = zft_blk_sz; | ||
422 | zft_last_vtbl->zft_volume = 1; | ||
423 | zft_last_vtbl->qic113 = zft_qic113; | ||
424 | zft_last_vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) | ||
425 | - zft_calc_tape_pos(zft_last_vtbl->start_seg)); | ||
426 | #endif | ||
427 | TRACE_EXIT 0; | ||
428 | } | ||
429 | |||
430 | /* this functions translates the failed_sector_log, misused as | ||
431 | * EOF-marker list, into a virtual volume table. The table mustn't be | ||
432 | * written to tape, because this would occupy the first data segment, | ||
433 | * which should be the volume table, but is actually the first segment | ||
434 | * that is filled with data (when using standard ftape). We assume, | ||
435 | * that we get a non-empty failed_sector_log. | ||
436 | */ | ||
437 | int zft_fake_volume_headers (eof_mark_union *eof_map, int num_failed_sectors) | ||
438 | { | ||
439 | unsigned int segment, sector; | ||
440 | int have_eom = 0; | ||
441 | int vol_no; | ||
442 | TRACE_FUN(ft_t_flow); | ||
443 | |||
444 | if ((num_failed_sectors >= 2) && | ||
445 | (GET2(&eof_map[num_failed_sectors - 1].mark.segment, 0) | ||
446 | == | ||
447 | GET2(&eof_map[num_failed_sectors - 2].mark.segment, 0) + 1) && | ||
448 | (GET2(&eof_map[num_failed_sectors - 1].mark.date, 0) == 1)) { | ||
449 | /* this should be eom. We keep the remainder of the | ||
450 | * tape as another volume. | ||
451 | */ | ||
452 | have_eom = 1; | ||
453 | } | ||
454 | zft_init_vtbl(); | ||
455 | zft_eom_vtbl->start_seg = ft_first_data_segment; | ||
456 | for(vol_no = 0; vol_no < num_failed_sectors - have_eom; vol_no ++) { | ||
457 | zft_new_vtbl_entry(); | ||
458 | |||
459 | segment = GET2(&eof_map[vol_no].mark.segment, 0); | ||
460 | sector = GET2(&eof_map[vol_no].mark.date, 0); | ||
461 | |||
462 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
463 | zft_last_vtbl->end_seg = segment; | ||
464 | zft_eom_vtbl->start_seg = segment + 1; | ||
465 | zft_last_vtbl->blk_sz = 1; | ||
466 | zft_last_vtbl->size = | ||
467 | (zft_calc_tape_pos(zft_last_vtbl->end_seg) | ||
468 | - zft_calc_tape_pos(zft_last_vtbl->start_seg) | ||
469 | + (sector-1) * FT_SECTOR_SIZE); | ||
470 | TRACE(ft_t_noise, | ||
471 | "failed sector log: segment: %d, sector: %d", | ||
472 | segment, sector); | ||
473 | DUMP_VOLINFO(ft_t_noise, "Faked volume", zft_last_vtbl); | ||
474 | } | ||
475 | if (!have_eom) { | ||
476 | zft_new_vtbl_entry(); | ||
477 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
478 | zft_last_vtbl->end_seg = ft_last_data_segment; | ||
479 | zft_eom_vtbl->start_seg = ft_last_data_segment + 1; | ||
480 | zft_last_vtbl->size = zft_capacity; | ||
481 | zft_last_vtbl->size -= zft_calc_tape_pos(zft_last_vtbl->start_seg); | ||
482 | zft_last_vtbl->blk_sz = 1; | ||
483 | DUMP_VOLINFO(ft_t_noise, "Faked volume",zft_last_vtbl); | ||
484 | } | ||
485 | TRACE_EXIT 0; | ||
486 | } | ||
487 | |||
488 | /* update the internal volume table | ||
489 | * | ||
490 | * if before start of last volume: erase all following volumes if | ||
491 | * inside a volume: set end of volume to infinity | ||
492 | * | ||
493 | * this function is intended to be called every time _ftape_write() is | ||
494 | * called | ||
495 | * | ||
496 | * return: 0 if no new volume was created, 1 if a new volume was | ||
497 | * created | ||
498 | * | ||
499 | * NOTE: we don't need to check for zft_mode as ftape_write() does | ||
500 | * that already. This function gets never called without accessing | ||
501 | * zftape via the *qft* devices | ||
502 | */ | ||
503 | |||
504 | int zft_open_volume(zft_position *pos, int blk_sz, int use_compression) | ||
505 | { | ||
506 | TRACE_FUN(ft_t_flow); | ||
507 | |||
508 | if (!zft_qic_mode) { | ||
509 | TRACE_EXIT 0; | ||
510 | } | ||
511 | if (zft_tape_at_lbot(pos)) { | ||
512 | zft_init_vtbl(); | ||
513 | if(zft_old_ftape) { | ||
514 | /* clear old ftape's eof marks */ | ||
515 | zft_clear_ftape_file_marks(); | ||
516 | zft_old_ftape = 0; /* no longer old ftape */ | ||
517 | } | ||
518 | zft_reset_position(pos); | ||
519 | } | ||
520 | if (pos->seg_pos != zft_last_vtbl->end_seg + 1) { | ||
521 | TRACE_ABORT(-EIO, ft_t_bug, | ||
522 | "BUG: seg_pos: %d, zft_last_vtbl->end_seg: %d", | ||
523 | pos->seg_pos, zft_last_vtbl->end_seg); | ||
524 | } | ||
525 | TRACE(ft_t_noise, "create new volume"); | ||
526 | if (zft_eom_vtbl->count >= ZFT_MAX_VOLUMES) { | ||
527 | TRACE_ABORT(-ENOSPC, ft_t_err, | ||
528 | "Error: maxmimal number of volumes exhausted " | ||
529 | "(maxmimum is %d)", ZFT_MAX_VOLUMES); | ||
530 | } | ||
531 | zft_new_vtbl_entry(); | ||
532 | pos->volume_pos = pos->seg_byte_pos = 0; | ||
533 | zft_last_vtbl->start_seg = pos->seg_pos; | ||
534 | zft_last_vtbl->end_seg = ft_last_data_segment; /* infinity */ | ||
535 | zft_last_vtbl->blk_sz = blk_sz; | ||
536 | zft_last_vtbl->size = zft_capacity; | ||
537 | zft_last_vtbl->zft_volume = 1; | ||
538 | zft_last_vtbl->use_compression = use_compression; | ||
539 | zft_last_vtbl->qic113 = zft_qic113; | ||
540 | zft_last_vtbl->new_volume = 1; | ||
541 | zft_last_vtbl->open = 1; | ||
542 | zft_volume_table_changed = 1; | ||
543 | zft_eom_vtbl->start_seg = ft_last_data_segment + 1; | ||
544 | TRACE_EXIT 0; | ||
545 | } | ||
546 | |||
547 | /* perform mtfsf, mtbsf, not allowed without zft_qic_mode | ||
548 | */ | ||
549 | int zft_skip_volumes(int count, zft_position *pos) | ||
550 | { | ||
551 | const zft_volinfo *vtbl; | ||
552 | TRACE_FUN(ft_t_flow); | ||
553 | |||
554 | TRACE(ft_t_noise, "count: %d", count); | ||
555 | |||
556 | vtbl= zft_find_volume(pos->seg_pos); | ||
557 | while (count > 0 && vtbl != zft_eom_vtbl) { | ||
558 | vtbl = list_entry(vtbl->node.next, zft_volinfo, node); | ||
559 | count --; | ||
560 | } | ||
561 | while (count < 0 && vtbl != zft_first_vtbl) { | ||
562 | vtbl = list_entry(vtbl->node.prev, zft_volinfo, node); | ||
563 | count ++; | ||
564 | } | ||
565 | pos->seg_pos = vtbl->start_seg; | ||
566 | pos->seg_byte_pos = 0; | ||
567 | pos->volume_pos = 0; | ||
568 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
569 | zft_just_before_eof = vtbl->size == 0; | ||
570 | if (zft_cmpr_ops) { | ||
571 | (*zft_cmpr_ops->reset)(); | ||
572 | } | ||
573 | zft_deblock_segment = -1; /* no need to keep cache */ | ||
574 | TRACE(ft_t_noise, "repositioning to:\n" | ||
575 | KERN_INFO "zft_seg_pos : %d\n" | ||
576 | KERN_INFO "zft_seg_byte_pos : %d\n" | ||
577 | KERN_INFO "zft_tape_pos : " LL_X "\n" | ||
578 | KERN_INFO "zft_volume_pos : " LL_X "\n" | ||
579 | KERN_INFO "file number : %d", | ||
580 | pos->seg_pos, pos->seg_byte_pos, | ||
581 | LL(pos->tape_pos), LL(pos->volume_pos), vtbl->count); | ||
582 | zft_resid = count < 0 ? -count : count; | ||
583 | TRACE_EXIT zft_resid ? -EINVAL : 0; | ||
584 | } | ||
585 | |||
586 | /* the following simply returns the raw data position of the EOM | ||
587 | * marker, MTIOCSIZE ioctl | ||
588 | */ | ||
589 | __s64 zft_get_eom_pos(void) | ||
590 | { | ||
591 | if (zft_qic_mode) { | ||
592 | return zft_calc_tape_pos(zft_eom_vtbl->start_seg); | ||
593 | } else { | ||
594 | /* there is only one volume in raw mode */ | ||
595 | return zft_capacity; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | /* skip to eom, used for MTEOM | ||
600 | */ | ||
601 | void zft_skip_to_eom(zft_position *pos) | ||
602 | { | ||
603 | TRACE_FUN(ft_t_flow); | ||
604 | pos->seg_pos = zft_eom_vtbl->start_seg; | ||
605 | pos->seg_byte_pos = | ||
606 | pos->volume_pos = | ||
607 | zft_just_before_eof = 0; | ||
608 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
609 | TRACE(ft_t_noise, "ftape positioned to segment %d, data pos " LL_X, | ||
610 | pos->seg_pos, LL(pos->tape_pos)); | ||
611 | TRACE_EXIT; | ||
612 | } | ||
613 | |||
614 | /* write an EOF-marker by setting zft_last_vtbl->end_seg to seg_pos. | ||
615 | * NOTE: this function assumes that zft_last_vtbl points to a valid | ||
616 | * vtbl entry | ||
617 | * | ||
618 | * NOTE: this routine always positions before the EOF marker | ||
619 | */ | ||
620 | int zft_close_volume(zft_position *pos) | ||
621 | { | ||
622 | TRACE_FUN(ft_t_any); | ||
623 | |||
624 | if (zft_vtbl_empty || !zft_last_vtbl->open) { /* should not happen */ | ||
625 | TRACE(ft_t_noise, "There are no volumes to finish"); | ||
626 | TRACE_EXIT -EIO; | ||
627 | } | ||
628 | if (pos->seg_byte_pos == 0 && | ||
629 | pos->seg_pos != zft_last_vtbl->start_seg) { | ||
630 | pos->seg_pos --; | ||
631 | pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos); | ||
632 | } | ||
633 | zft_last_vtbl->end_seg = pos->seg_pos; | ||
634 | zft_last_vtbl->size = pos->volume_pos; | ||
635 | zft_volume_table_changed = 1; | ||
636 | zft_just_before_eof = 1; | ||
637 | zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1; | ||
638 | zft_last_vtbl->open = 0; /* closed */ | ||
639 | TRACE_EXIT 0; | ||
640 | } | ||
641 | |||
642 | /* write count file-marks at current position. | ||
643 | * | ||
644 | * The tape is positioned after the eof-marker, that is at byte 0 of | ||
645 | * the segment following the eof-marker | ||
646 | * | ||
647 | * this function is only allowed in zft_qic_mode | ||
648 | * | ||
649 | * Only allowed when tape is at BOT or EOD. | ||
650 | */ | ||
651 | int zft_weof(unsigned int count, zft_position *pos) | ||
652 | { | ||
653 | |||
654 | TRACE_FUN(ft_t_flow); | ||
655 | |||
656 | if (!count) { /* write zero EOF marks should be a real no-op */ | ||
657 | TRACE_EXIT 0; | ||
658 | } | ||
659 | zft_volume_table_changed = 1; | ||
660 | if (zft_tape_at_lbot(pos)) { | ||
661 | zft_init_vtbl(); | ||
662 | if(zft_old_ftape) { | ||
663 | /* clear old ftape's eof marks */ | ||
664 | zft_clear_ftape_file_marks(); | ||
665 | zft_old_ftape = 0; /* no longer old ftape */ | ||
666 | } | ||
667 | } | ||
668 | if (zft_last_vtbl->open) { | ||
669 | zft_close_volume(pos); | ||
670 | zft_move_past_eof(pos); | ||
671 | count --; | ||
672 | } | ||
673 | /* now it's easy, just append eof-marks, that is empty | ||
674 | * volumes, to the end of the already recorded media. | ||
675 | */ | ||
676 | while (count > 0 && | ||
677 | pos->seg_pos <= ft_last_data_segment && | ||
678 | zft_eom_vtbl->count < ZFT_MAX_VOLUMES) { | ||
679 | TRACE(ft_t_noise, | ||
680 | "Writing zero sized file at segment %d", pos->seg_pos); | ||
681 | zft_new_vtbl_entry(); | ||
682 | zft_last_vtbl->start_seg = pos->seg_pos; | ||
683 | zft_last_vtbl->end_seg = pos->seg_pos; | ||
684 | zft_last_vtbl->size = 0; | ||
685 | zft_last_vtbl->blk_sz = zft_blk_sz; | ||
686 | zft_last_vtbl->zft_volume = 1; | ||
687 | zft_last_vtbl->use_compression = 0; | ||
688 | pos->tape_pos += zft_get_seg_sz(pos->seg_pos); | ||
689 | zft_eom_vtbl->start_seg = ++ pos->seg_pos; | ||
690 | count --; | ||
691 | } | ||
692 | if (count > 0) { | ||
693 | /* there are two possibilities: end of tape, or the | ||
694 | * maximum number of files is exhausted. | ||
695 | */ | ||
696 | zft_resid = count; | ||
697 | TRACE(ft_t_noise,"Number of marks NOT written: %d", zft_resid); | ||
698 | if (zft_eom_vtbl->count == ZFT_MAX_VOLUMES) { | ||
699 | TRACE_ABORT(-EINVAL, ft_t_warn, | ||
700 | "maximum allowed number of files " | ||
701 | "exhausted: %d", ZFT_MAX_VOLUMES); | ||
702 | } else { | ||
703 | TRACE_ABORT(-ENOSPC, | ||
704 | ft_t_noise, "reached end of tape"); | ||
705 | } | ||
706 | } | ||
707 | TRACE_EXIT 0; | ||
708 | } | ||
709 | |||
710 | const zft_volinfo *zft_find_volume(unsigned int seg_pos) | ||
711 | { | ||
712 | TRACE_FUN(ft_t_flow); | ||
713 | |||
714 | TRACE(ft_t_any, "called with seg_pos %d",seg_pos); | ||
715 | if (!zft_qic_mode) { | ||
716 | if (seg_pos > ft_last_data_segment) { | ||
717 | TRACE_EXIT &eot_vtbl; | ||
718 | } | ||
719 | tape_vtbl.blk_sz = zft_blk_sz; | ||
720 | TRACE_EXIT &tape_vtbl; | ||
721 | } | ||
722 | if (seg_pos < zft_first_vtbl->start_seg) { | ||
723 | TRACE_EXIT (cur_vtbl = zft_first_vtbl); | ||
724 | } | ||
725 | while (seg_pos > cur_vtbl->end_seg) { | ||
726 | cur_vtbl = list_entry(cur_vtbl->node.next, zft_volinfo, node); | ||
727 | TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg); | ||
728 | } | ||
729 | while (seg_pos < cur_vtbl->start_seg) { | ||
730 | cur_vtbl = list_entry(cur_vtbl->node.prev, zft_volinfo, node); | ||
731 | TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg); | ||
732 | } | ||
733 | if (seg_pos > cur_vtbl->end_seg || seg_pos < cur_vtbl->start_seg) { | ||
734 | TRACE(ft_t_bug, "This cannot happen"); | ||
735 | } | ||
736 | DUMP_VOLINFO(ft_t_noise, "", cur_vtbl); | ||
737 | TRACE_EXIT cur_vtbl; | ||
738 | } | ||
739 | |||
740 | /* this function really assumes that we are just before eof | ||
741 | */ | ||
742 | void zft_move_past_eof(zft_position *pos) | ||
743 | { | ||
744 | TRACE_FUN(ft_t_flow); | ||
745 | |||
746 | TRACE(ft_t_noise, "old seg. pos: %d", pos->seg_pos); | ||
747 | pos->tape_pos += zft_get_seg_sz(pos->seg_pos++) - pos->seg_byte_pos; | ||
748 | pos->seg_byte_pos = 0; | ||
749 | pos->volume_pos = 0; | ||
750 | if (zft_cmpr_ops) { | ||
751 | (*zft_cmpr_ops->reset)(); | ||
752 | } | ||
753 | zft_just_before_eof = 0; | ||
754 | zft_deblock_segment = -1; /* no need to cache it anymore */ | ||
755 | TRACE(ft_t_noise, "new seg. pos: %d", pos->seg_pos); | ||
756 | TRACE_EXIT; | ||
757 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-vtbl.h b/drivers/char/ftape/zftape/zftape-vtbl.h deleted file mode 100644 index f31d196d1759..000000000000 --- a/drivers/char/ftape/zftape/zftape-vtbl.h +++ /dev/null | |||
@@ -1,227 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_VTBL_H | ||
2 | #define _ZFTAPE_VTBL_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (c) 1995-1997 Claus-Justus Heine | ||
6 | |||
7 | This program is free software; you can redistribute it and/or | ||
8 | modify it under the terms of the GNU General Public License as | ||
9 | published by the Free Software Foundation; either version 2, or (at | ||
10 | your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, but | ||
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | 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, | ||
20 | USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.h,v $ | ||
24 | * $Revision: 1.3 $ | ||
25 | * $Date: 1997/10/28 14:30:09 $ | ||
26 | * | ||
27 | * This file defines a volume table as defined in the QIC-80 | ||
28 | * development standards. | ||
29 | */ | ||
30 | |||
31 | #include <linux/list.h> | ||
32 | |||
33 | #include "../lowlevel/ftape-tracing.h" | ||
34 | |||
35 | #include "../zftape/zftape-eof.h" | ||
36 | #include "../zftape/zftape-ctl.h" | ||
37 | #include "../zftape/zftape-rw.h" | ||
38 | |||
39 | #define VTBL_SIZE 128 /* bytes */ | ||
40 | |||
41 | /* The following are offsets in the vtbl. */ | ||
42 | #define VTBL_SIG 0 | ||
43 | #define VTBL_START 4 | ||
44 | #define VTBL_END 6 | ||
45 | #define VTBL_DESC 8 | ||
46 | #define VTBL_DATE 52 | ||
47 | #define VTBL_FLAGS 56 | ||
48 | #define VTBL_FL_VENDOR_SPECIFIC (1<<0) | ||
49 | #define VTBL_FL_MUTLI_CARTRIDGE (1<<1) | ||
50 | #define VTBL_FL_NOT_VERIFIED (1<<2) | ||
51 | #define VTBL_FL_REDIR_INHIBIT (1<<3) | ||
52 | #define VTBL_FL_SEG_SPANNING (1<<4) | ||
53 | #define VTBL_FL_DIRECTORY_LAST (1<<5) | ||
54 | #define VTBL_FL_RESERVED_6 (1<<6) | ||
55 | #define VTBL_FL_RESERVED_7 (1<<7) | ||
56 | #define VTBL_M_NO 57 | ||
57 | #define VTBL_EXT 58 | ||
58 | #define EXT_ZFTAPE_SIG 0 | ||
59 | #define EXT_ZFTAPE_BLKSZ 10 | ||
60 | #define EXT_ZFTAPE_CMAP 12 | ||
61 | #define EXT_ZFTAPE_QIC113 13 | ||
62 | #define VTBL_PWD 84 | ||
63 | #define VTBL_DIR_SIZE 92 | ||
64 | #define VTBL_DATA_SIZE 96 | ||
65 | #define VTBL_OS_VERSION 104 | ||
66 | #define VTBL_SRC_DRIVE 106 | ||
67 | #define VTBL_DEV 122 | ||
68 | #define VTBL_RESERVED_1 123 | ||
69 | #define VTBL_CMPR 124 | ||
70 | #define VTBL_CMPR_UNREG 0x3f | ||
71 | #define VTBL_CMPR_USED 0x80 | ||
72 | #define VTBL_FMT 125 | ||
73 | #define VTBL_RESERVED_2 126 | ||
74 | #define VTBL_RESERVED_3 127 | ||
75 | /* compatibility with pre revision K */ | ||
76 | #define VTBL_K_CMPR 120 | ||
77 | |||
78 | /* the next is used by QIC-3020 tapes with format code 6 (>2^16 | ||
79 | * segments) It is specified in QIC-113, Rev. G, Section 5 (SCSI | ||
80 | * volume table). The difference is simply, that we only store the | ||
81 | * number of segments used, not the starting segment. | ||
82 | */ | ||
83 | #define VTBL_SCSI_SEGS 4 /* is a 4 byte value */ | ||
84 | |||
85 | /* one vtbl is 128 bytes, that results in a maximum number of | ||
86 | * 29*1024/128 = 232 volumes. | ||
87 | */ | ||
88 | #define ZFT_MAX_VOLUMES (FT_SEGMENT_SIZE/VTBL_SIZE) | ||
89 | #define VTBL_ID "VTBL" | ||
90 | #define VTBL_IDS { VTBL_ID, "XTBL", "UTID", "EXVT" } /* other valid ids */ | ||
91 | #define ZFT_VOL_NAME "zftape volume" /* volume label used by me */ | ||
92 | #define ZFTAPE_SIG "LINUX ZFT" | ||
93 | |||
94 | /* global variables | ||
95 | */ | ||
96 | typedef struct zft_internal_vtbl | ||
97 | { | ||
98 | struct list_head node; | ||
99 | int count; | ||
100 | unsigned int start_seg; /* 32 bits are enough for now */ | ||
101 | unsigned int end_seg; /* 32 bits are enough for now */ | ||
102 | __s64 size; /* uncompressed size */ | ||
103 | unsigned int blk_sz; /* block size for this volume */ | ||
104 | unsigned int zft_volume :1; /* zftape created this volume */ | ||
105 | unsigned int use_compression:1; /* compressed volume */ | ||
106 | unsigned int qic113 :1; /* layout of compressed block | ||
107 | * info and vtbl conforms to | ||
108 | * QIC-113, Rev. G | ||
109 | */ | ||
110 | unsigned int new_volume :1; /* it was created by us, this | ||
111 | * run. this allows the | ||
112 | * fields that aren't really | ||
113 | * used by zftape to be filled | ||
114 | * in by some user level | ||
115 | * program. | ||
116 | */ | ||
117 | unsigned int open :1; /* just in progress of being | ||
118 | * written | ||
119 | */ | ||
120 | } zft_volinfo; | ||
121 | |||
122 | extern struct list_head zft_vtbl; | ||
123 | #define zft_head_vtbl list_entry(zft_vtbl.next, zft_volinfo, node) | ||
124 | #define zft_eom_vtbl list_entry(zft_vtbl.prev, zft_volinfo, node) | ||
125 | #define zft_last_vtbl list_entry(zft_eom_vtbl->node.prev, zft_volinfo, node) | ||
126 | #define zft_first_vtbl list_entry(zft_head_vtbl->node.next, zft_volinfo, node) | ||
127 | #define zft_vtbl_empty (zft_eom_vtbl->node.prev == &zft_head_vtbl->node) | ||
128 | |||
129 | #define DUMP_VOLINFO(level, desc, info) \ | ||
130 | { \ | ||
131 | char tmp[21]; \ | ||
132 | strlcpy(tmp, desc, sizeof(tmp)); \ | ||
133 | TRACE(level, "Volume %d:\n" \ | ||
134 | KERN_INFO "description : %s\n" \ | ||
135 | KERN_INFO "first segment: %d\n" \ | ||
136 | KERN_INFO "last segment: %d\n" \ | ||
137 | KERN_INFO "size : " LL_X "\n" \ | ||
138 | KERN_INFO "block size : %d\n" \ | ||
139 | KERN_INFO "compression : %d\n" \ | ||
140 | KERN_INFO "zftape volume: %d\n" \ | ||
141 | KERN_INFO "QIC-113 conf.: %d", \ | ||
142 | (info)->count, tmp, (info)->start_seg, (info)->end_seg, \ | ||
143 | LL((info)->size), (info)->blk_sz, \ | ||
144 | (info)->use_compression != 0, (info)->zft_volume != 0, \ | ||
145 | (info)->qic113 != 0); \ | ||
146 | } | ||
147 | |||
148 | extern int zft_qic_mode; | ||
149 | extern int zft_old_ftape; | ||
150 | extern int zft_volume_table_changed; | ||
151 | |||
152 | /* exported functions */ | ||
153 | extern void zft_init_vtbl (void); | ||
154 | extern void zft_free_vtbl (void); | ||
155 | extern int zft_extract_volume_headers(__u8 *buffer); | ||
156 | extern int zft_update_volume_table (unsigned int segment); | ||
157 | extern int zft_open_volume (zft_position *pos, | ||
158 | int blk_sz, int use_compression); | ||
159 | extern int zft_close_volume (zft_position *pos); | ||
160 | extern const zft_volinfo *zft_find_volume(unsigned int seg_pos); | ||
161 | extern int zft_skip_volumes (int count, zft_position *pos); | ||
162 | extern __s64 zft_get_eom_pos (void); | ||
163 | extern void zft_skip_to_eom (zft_position *pos); | ||
164 | extern int zft_fake_volume_headers (eof_mark_union *eof_map, | ||
165 | int num_failed_sectors); | ||
166 | extern int zft_weof (unsigned int count, zft_position *pos); | ||
167 | extern void zft_move_past_eof (zft_position *pos); | ||
168 | |||
169 | static inline int zft_tape_at_eod (const zft_position *pos); | ||
170 | static inline int zft_tape_at_lbot (const zft_position *pos); | ||
171 | static inline void zft_position_before_eof (zft_position *pos, | ||
172 | const zft_volinfo *volume); | ||
173 | static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, | ||
174 | const zft_position *pos); | ||
175 | |||
176 | /* this function decrements the zft_seg_pos counter if we are right | ||
177 | * at the beginning of a segment. This is to handle fsfm/bsfm -- we | ||
178 | * need to position before the eof mark. NOTE: zft_tape_pos is not | ||
179 | * changed | ||
180 | */ | ||
181 | static inline void zft_position_before_eof(zft_position *pos, | ||
182 | const zft_volinfo *volume) | ||
183 | { | ||
184 | TRACE_FUN(ft_t_flow); | ||
185 | |||
186 | if (pos->seg_pos == volume->end_seg + 1 && pos->seg_byte_pos == 0) { | ||
187 | pos->seg_pos --; | ||
188 | pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos); | ||
189 | } | ||
190 | TRACE_EXIT; | ||
191 | } | ||
192 | |||
193 | /* Mmmh. Is the position at the end of the last volume, that is right | ||
194 | * before the last EOF mark also logical an EOD condition? | ||
195 | */ | ||
196 | static inline int zft_tape_at_eod(const zft_position *pos) | ||
197 | { | ||
198 | TRACE_FUN(ft_t_any); | ||
199 | |||
200 | if (zft_qic_mode) { | ||
201 | TRACE_EXIT (pos->seg_pos >= zft_eom_vtbl->start_seg || | ||
202 | zft_last_vtbl->open); | ||
203 | } else { | ||
204 | TRACE_EXIT pos->seg_pos > ft_last_data_segment; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static inline int zft_tape_at_lbot(const zft_position *pos) | ||
209 | { | ||
210 | if (zft_qic_mode) { | ||
211 | return (pos->seg_pos <= zft_first_vtbl->start_seg && | ||
212 | pos->volume_pos == 0); | ||
213 | } else { | ||
214 | return (pos->seg_pos <= ft_first_data_segment && | ||
215 | pos->volume_pos == 0); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | /* This one checks for EOF. return remaing space (may be negative) | ||
220 | */ | ||
221 | static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, | ||
222 | const zft_position *pos) | ||
223 | { | ||
224 | return (__s64)(vtbl->size - pos->volume_pos); | ||
225 | } | ||
226 | |||
227 | #endif /* _ZFTAPE_VTBL_H */ | ||
diff --git a/drivers/char/ftape/zftape/zftape-write.c b/drivers/char/ftape/zftape/zftape-write.c deleted file mode 100644 index 94327b8c97b9..000000000000 --- a/drivers/char/ftape/zftape/zftape-write.c +++ /dev/null | |||
@@ -1,483 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996, 1997 Claus 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/zftape/zftape-write.c,v $ | ||
20 | * $Revision: 1.3 $ | ||
21 | * $Date: 1997/11/06 00:50:29 $ | ||
22 | * | ||
23 | * This file contains the writing code | ||
24 | * for the QIC-117 floppy-tape driver for Linux. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | |||
30 | #include <linux/zftape.h> | ||
31 | |||
32 | #include <asm/uaccess.h> | ||
33 | |||
34 | #include "../zftape/zftape-init.h" | ||
35 | #include "../zftape/zftape-eof.h" | ||
36 | #include "../zftape/zftape-ctl.h" | ||
37 | #include "../zftape/zftape-write.h" | ||
38 | #include "../zftape/zftape-read.h" | ||
39 | #include "../zftape/zftape-rw.h" | ||
40 | #include "../zftape/zftape-vtbl.h" | ||
41 | |||
42 | /* Global vars. | ||
43 | */ | ||
44 | |||
45 | /* Local vars. | ||
46 | */ | ||
47 | static int last_write_failed; | ||
48 | static int need_flush; | ||
49 | |||
50 | void zft_prevent_flush(void) | ||
51 | { | ||
52 | need_flush = 0; | ||
53 | } | ||
54 | |||
55 | static int zft_write_header_segments(__u8* buffer) | ||
56 | { | ||
57 | int header_1_ok = 0; | ||
58 | int header_2_ok = 0; | ||
59 | unsigned int time_stamp; | ||
60 | TRACE_FUN(ft_t_noise); | ||
61 | |||
62 | TRACE_CATCH(ftape_abort_operation(),); | ||
63 | ftape_seek_to_bot(); /* prevents extra rewind */ | ||
64 | if (GET4(buffer, 0) != FT_HSEG_MAGIC) { | ||
65 | TRACE_ABORT(-EIO, ft_t_err, | ||
66 | "wrong header signature found, aborting"); | ||
67 | } | ||
68 | /* Be optimistic: */ | ||
69 | PUT4(buffer, FT_SEG_CNT, | ||
70 | zft_written_segments + GET4(buffer, FT_SEG_CNT) + 2); | ||
71 | if ((time_stamp = zft_get_time()) != 0) { | ||
72 | PUT4(buffer, FT_WR_DATE, time_stamp); | ||
73 | if (zft_label_changed) { | ||
74 | PUT4(buffer, FT_LABEL_DATE, time_stamp); | ||
75 | } | ||
76 | } | ||
77 | TRACE(ft_t_noise, | ||
78 | "writing first header segment %d", ft_header_segment_1); | ||
79 | header_1_ok = zft_verify_write_segments(ft_header_segment_1, | ||
80 | buffer, FT_SEGMENT_SIZE, | ||
81 | zft_deblock_buf) >= 0; | ||
82 | TRACE(ft_t_noise, | ||
83 | "writing second header segment %d", ft_header_segment_2); | ||
84 | header_2_ok = zft_verify_write_segments(ft_header_segment_2, | ||
85 | buffer, FT_SEGMENT_SIZE, | ||
86 | zft_deblock_buf) >= 0; | ||
87 | if (!header_1_ok) { | ||
88 | TRACE(ft_t_warn, "Warning: " | ||
89 | "update of first header segment failed"); | ||
90 | } | ||
91 | if (!header_2_ok) { | ||
92 | TRACE(ft_t_warn, "Warning: " | ||
93 | "update of second header segment failed"); | ||
94 | } | ||
95 | if (!header_1_ok && !header_2_ok) { | ||
96 | TRACE_ABORT(-EIO, ft_t_err, "Error: " | ||
97 | "update of both header segments failed."); | ||
98 | } | ||
99 | TRACE_EXIT 0; | ||
100 | } | ||
101 | |||
102 | int zft_update_header_segments(void) | ||
103 | { | ||
104 | TRACE_FUN(ft_t_noise); | ||
105 | |||
106 | /* must NOT use zft_write_protected, as it also includes the | ||
107 | * file access mode. But we also want to update when soft | ||
108 | * write protection is enabled (O_RDONLY) | ||
109 | */ | ||
110 | if (ft_write_protected || zft_old_ftape) { | ||
111 | TRACE_ABORT(0, ft_t_noise, "Tape set read-only: no update"); | ||
112 | } | ||
113 | if (!zft_header_read) { | ||
114 | TRACE_ABORT(0, ft_t_noise, "Nothing to update"); | ||
115 | } | ||
116 | if (!zft_header_changed) { | ||
117 | zft_header_changed = zft_written_segments > 0; | ||
118 | } | ||
119 | if (!zft_header_changed && !zft_volume_table_changed) { | ||
120 | TRACE_ABORT(0, ft_t_noise, "Nothing to update"); | ||
121 | } | ||
122 | TRACE(ft_t_noise, "Updating header segments"); | ||
123 | if (ftape_get_status()->fti_state == writing) { | ||
124 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
125 | } | ||
126 | TRACE_CATCH(ftape_abort_operation(),); | ||
127 | |||
128 | zft_deblock_segment = -1; /* invalidate the cache */ | ||
129 | if (zft_header_changed) { | ||
130 | TRACE_CATCH(zft_write_header_segments(zft_hseg_buf),); | ||
131 | } | ||
132 | if (zft_volume_table_changed) { | ||
133 | TRACE_CATCH(zft_update_volume_table(ft_first_data_segment),); | ||
134 | } | ||
135 | zft_header_changed = | ||
136 | zft_volume_table_changed = | ||
137 | zft_label_changed = | ||
138 | zft_written_segments = 0; | ||
139 | TRACE_CATCH(ftape_abort_operation(),); | ||
140 | ftape_seek_to_bot(); | ||
141 | TRACE_EXIT 0; | ||
142 | } | ||
143 | |||
144 | static int read_merge_buffer(int seg_pos, __u8 *buffer, int offset, int seg_sz) | ||
145 | { | ||
146 | int result = 0; | ||
147 | const ft_trace_t old_tracing = TRACE_LEVEL; | ||
148 | TRACE_FUN(ft_t_flow); | ||
149 | |||
150 | if (zft_qic_mode) { | ||
151 | /* writing in the middle of a volume is NOT allowed | ||
152 | * | ||
153 | */ | ||
154 | TRACE(ft_t_noise, "No need to read a segment"); | ||
155 | memset(buffer + offset, 0, seg_sz - offset); | ||
156 | TRACE_EXIT 0; | ||
157 | } | ||
158 | TRACE(ft_t_any, "waiting"); | ||
159 | ftape_start_writing(FT_WR_MULTI); | ||
160 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
161 | |||
162 | TRACE(ft_t_noise, "trying to read segment %d from offset %d", | ||
163 | seg_pos, offset); | ||
164 | SET_TRACE_LEVEL(ft_t_bug); | ||
165 | result = zft_fetch_segment_fraction(seg_pos, buffer, | ||
166 | FT_RD_SINGLE, | ||
167 | offset, seg_sz - offset); | ||
168 | SET_TRACE_LEVEL(old_tracing); | ||
169 | if (result != (seg_sz - offset)) { | ||
170 | TRACE(ft_t_noise, "Ignore error: read_segment() result: %d", | ||
171 | result); | ||
172 | memset(buffer + offset, 0, seg_sz - offset); | ||
173 | } | ||
174 | TRACE_EXIT 0; | ||
175 | } | ||
176 | |||
177 | /* flush the write buffer to tape and write an eof-marker at the | ||
178 | * current position if not in raw mode. This function always | ||
179 | * positions the tape before the eof-marker. _ftape_close() should | ||
180 | * then advance to the next segment. | ||
181 | * | ||
182 | * the parameter "finish_volume" describes whether to position before | ||
183 | * or after the possibly created file-mark. We always position after | ||
184 | * the file-mark when called from ftape_close() and a flush was needed | ||
185 | * (that is ftape_write() was the last tape operation before calling | ||
186 | * ftape_flush) But we always position before the file-mark when this | ||
187 | * function get's called from outside ftape_close() | ||
188 | */ | ||
189 | int zft_flush_buffers(void) | ||
190 | { | ||
191 | int result; | ||
192 | int data_remaining; | ||
193 | int this_segs_size; | ||
194 | TRACE_FUN(ft_t_flow); | ||
195 | |||
196 | TRACE(ft_t_data_flow, | ||
197 | "entered, ftape_state = %d", ftape_get_status()->fti_state); | ||
198 | if (ftape_get_status()->fti_state != writing && !need_flush) { | ||
199 | TRACE_ABORT(0, ft_t_noise, "no need for flush"); | ||
200 | } | ||
201 | zft_io_state = zft_idle; /* triggers some initializations for the | ||
202 | * read and write routines | ||
203 | */ | ||
204 | if (last_write_failed) { | ||
205 | ftape_abort_operation(); | ||
206 | TRACE_EXIT -EIO; | ||
207 | } | ||
208 | TRACE(ft_t_noise, "flushing write buffers"); | ||
209 | this_segs_size = zft_get_seg_sz(zft_pos.seg_pos); | ||
210 | if (this_segs_size == zft_pos.seg_byte_pos) { | ||
211 | zft_pos.seg_pos ++; | ||
212 | data_remaining = zft_pos.seg_byte_pos = 0; | ||
213 | } else { | ||
214 | data_remaining = zft_pos.seg_byte_pos; | ||
215 | } | ||
216 | /* If there is any data not written to tape yet, append zero's | ||
217 | * up to the end of the sector (if using compression) or merge | ||
218 | * it with the data existing on the tape Then write the | ||
219 | * segment(s) to tape. | ||
220 | */ | ||
221 | TRACE(ft_t_noise, "Position:\n" | ||
222 | KERN_INFO "seg_pos : %d\n" | ||
223 | KERN_INFO "byte pos : %d\n" | ||
224 | KERN_INFO "remaining: %d", | ||
225 | zft_pos.seg_pos, zft_pos.seg_byte_pos, data_remaining); | ||
226 | if (data_remaining > 0) { | ||
227 | do { | ||
228 | this_segs_size = zft_get_seg_sz(zft_pos.seg_pos); | ||
229 | if (this_segs_size > data_remaining) { | ||
230 | TRACE_CATCH(read_merge_buffer(zft_pos.seg_pos, | ||
231 | zft_deblock_buf, | ||
232 | data_remaining, | ||
233 | this_segs_size), | ||
234 | last_write_failed = 1); | ||
235 | } | ||
236 | result = ftape_write_segment(zft_pos.seg_pos, | ||
237 | zft_deblock_buf, | ||
238 | FT_WR_MULTI); | ||
239 | if (result != this_segs_size) { | ||
240 | TRACE(ft_t_err, "flush buffers failed"); | ||
241 | zft_pos.tape_pos -= zft_pos.seg_byte_pos; | ||
242 | zft_pos.seg_byte_pos = 0; | ||
243 | |||
244 | last_write_failed = 1; | ||
245 | TRACE_EXIT result; | ||
246 | } | ||
247 | zft_written_segments ++; | ||
248 | TRACE(ft_t_data_flow, | ||
249 | "flush, moved out buffer: %d", result); | ||
250 | /* need next segment for more data (empty segments?) | ||
251 | */ | ||
252 | if (result < data_remaining) { | ||
253 | if (result > 0) { | ||
254 | /* move remainder to buffer beginning | ||
255 | */ | ||
256 | memmove(zft_deblock_buf, | ||
257 | zft_deblock_buf + result, | ||
258 | FT_SEGMENT_SIZE - result); | ||
259 | } | ||
260 | } | ||
261 | data_remaining -= result; | ||
262 | zft_pos.seg_pos ++; | ||
263 | } while (data_remaining > 0); | ||
264 | TRACE(ft_t_any, "result: %d", result); | ||
265 | zft_deblock_segment = --zft_pos.seg_pos; | ||
266 | if (data_remaining == 0) { /* first byte next segment */ | ||
267 | zft_pos.seg_byte_pos = this_segs_size; | ||
268 | } else { /* after data previous segment, data_remaining < 0 */ | ||
269 | zft_pos.seg_byte_pos = data_remaining + result; | ||
270 | } | ||
271 | } else { | ||
272 | TRACE(ft_t_noise, "zft_deblock_buf empty"); | ||
273 | zft_pos.seg_pos --; | ||
274 | zft_pos.seg_byte_pos = zft_get_seg_sz (zft_pos.seg_pos); | ||
275 | ftape_start_writing(FT_WR_MULTI); | ||
276 | } | ||
277 | TRACE(ft_t_any, "waiting"); | ||
278 | if ((result = ftape_loop_until_writes_done()) < 0) { | ||
279 | /* that's really bad. What to to with zft_tape_pos? | ||
280 | */ | ||
281 | TRACE(ft_t_err, "flush buffers failed"); | ||
282 | } | ||
283 | TRACE(ft_t_any, "zft_seg_pos: %d, zft_seg_byte_pos: %d", | ||
284 | zft_pos.seg_pos, zft_pos.seg_byte_pos); | ||
285 | last_write_failed = | ||
286 | need_flush = 0; | ||
287 | TRACE_EXIT result; | ||
288 | } | ||
289 | |||
290 | /* return-value: the number of bytes removed from the user-buffer | ||
291 | * | ||
292 | * out: | ||
293 | * int *write_cnt: how much actually has been moved to the | ||
294 | * zft_deblock_buf | ||
295 | * int req_len : MUST NOT BE CHANGED, except at EOT, in | ||
296 | * which case it may be adjusted | ||
297 | * in : | ||
298 | * char *buff : the user buffer | ||
299 | * int buf_pos_write : copy of buf_len_wr int | ||
300 | * this_segs_size : the size in bytes of the actual segment | ||
301 | * char | ||
302 | * *zft_deblock_buf : zft_deblock_buf | ||
303 | */ | ||
304 | static int zft_simple_write(int *cnt, | ||
305 | __u8 *dst_buf, const int seg_sz, | ||
306 | const __u8 __user *src_buf, const int req_len, | ||
307 | const zft_position *pos,const zft_volinfo *volume) | ||
308 | { | ||
309 | int space_left; | ||
310 | TRACE_FUN(ft_t_flow); | ||
311 | |||
312 | /* volume->size holds the tape capacity while volume is open */ | ||
313 | if (pos->tape_pos + volume->blk_sz > volume->size) { | ||
314 | TRACE_EXIT -ENOSPC; | ||
315 | } | ||
316 | /* remaining space in this segment, NOT zft_deblock_buf | ||
317 | */ | ||
318 | space_left = seg_sz - pos->seg_byte_pos; | ||
319 | *cnt = req_len < space_left ? req_len : space_left; | ||
320 | if (copy_from_user(dst_buf + pos->seg_byte_pos, src_buf, *cnt) != 0) { | ||
321 | TRACE_EXIT -EFAULT; | ||
322 | } | ||
323 | TRACE_EXIT *cnt; | ||
324 | } | ||
325 | |||
326 | static int check_write_access(int req_len, | ||
327 | const zft_volinfo **volume, | ||
328 | zft_position *pos, | ||
329 | const unsigned int blk_sz) | ||
330 | { | ||
331 | int result; | ||
332 | TRACE_FUN(ft_t_flow); | ||
333 | |||
334 | if ((req_len % zft_blk_sz) != 0) { | ||
335 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
336 | "write-count %d must be multiple of block-size %d", | ||
337 | req_len, blk_sz); | ||
338 | } | ||
339 | if (zft_io_state == zft_writing) { | ||
340 | /* all other error conditions have been checked earlier | ||
341 | */ | ||
342 | TRACE_EXIT 0; | ||
343 | } | ||
344 | zft_io_state = zft_idle; | ||
345 | TRACE_CATCH(zft_check_write_access(pos),); | ||
346 | /* If we haven't read the header segment yet, do it now. | ||
347 | * This will verify the configuration, get the bad sector | ||
348 | * table and read the volume table segment | ||
349 | */ | ||
350 | if (!zft_header_read) { | ||
351 | TRACE_CATCH(zft_read_header_segments(),); | ||
352 | } | ||
353 | /* fine. Now the tape is either at BOT or at EOD, | ||
354 | * Write start of volume now | ||
355 | */ | ||
356 | TRACE_CATCH(zft_open_volume(pos, blk_sz, zft_use_compression),); | ||
357 | *volume = zft_find_volume(pos->seg_pos); | ||
358 | DUMP_VOLINFO(ft_t_noise, "", *volume); | ||
359 | zft_just_before_eof = 0; | ||
360 | /* now merge with old data if necessary */ | ||
361 | if (!zft_qic_mode && pos->seg_byte_pos != 0){ | ||
362 | result = zft_fetch_segment(pos->seg_pos, | ||
363 | zft_deblock_buf, | ||
364 | FT_RD_SINGLE); | ||
365 | if (result < 0) { | ||
366 | if (result == -EINTR || result == -ENOSPC) { | ||
367 | TRACE_EXIT result; | ||
368 | } | ||
369 | TRACE(ft_t_noise, | ||
370 | "ftape_read_segment() result: %d. " | ||
371 | "This might be normal when using " | ||
372 | "a newly\nformatted tape", result); | ||
373 | memset(zft_deblock_buf, '\0', pos->seg_byte_pos); | ||
374 | } | ||
375 | } | ||
376 | zft_io_state = zft_writing; | ||
377 | TRACE_EXIT 0; | ||
378 | } | ||
379 | |||
380 | static int fill_deblock_buf(__u8 *dst_buf, const int seg_sz, | ||
381 | zft_position *pos, const zft_volinfo *volume, | ||
382 | const char __user *usr_buf, const int req_len) | ||
383 | { | ||
384 | int cnt = 0; | ||
385 | int result = 0; | ||
386 | TRACE_FUN(ft_t_flow); | ||
387 | |||
388 | if (seg_sz == 0) { | ||
389 | TRACE_ABORT(0, ft_t_data_flow, "empty segment"); | ||
390 | } | ||
391 | TRACE(ft_t_data_flow, "\n" | ||
392 | KERN_INFO "remaining req_len: %d\n" | ||
393 | KERN_INFO " buf_pos: %d", | ||
394 | req_len, pos->seg_byte_pos); | ||
395 | /* zft_deblock_buf will not contain a valid segment any longer */ | ||
396 | zft_deblock_segment = -1; | ||
397 | if (zft_use_compression) { | ||
398 | TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); | ||
399 | TRACE_CATCH(result= (*zft_cmpr_ops->write)(&cnt, | ||
400 | dst_buf, seg_sz, | ||
401 | usr_buf, req_len, | ||
402 | pos, volume),); | ||
403 | } else { | ||
404 | TRACE_CATCH(result= zft_simple_write(&cnt, | ||
405 | dst_buf, seg_sz, | ||
406 | usr_buf, req_len, | ||
407 | pos, volume),); | ||
408 | } | ||
409 | pos->volume_pos += result; | ||
410 | pos->seg_byte_pos += cnt; | ||
411 | pos->tape_pos += cnt; | ||
412 | TRACE(ft_t_data_flow, "\n" | ||
413 | KERN_INFO "removed from user-buffer : %d bytes.\n" | ||
414 | KERN_INFO "copied to zft_deblock_buf: %d bytes.\n" | ||
415 | KERN_INFO "zft_tape_pos : " LL_X " bytes.", | ||
416 | result, cnt, LL(pos->tape_pos)); | ||
417 | TRACE_EXIT result; | ||
418 | } | ||
419 | |||
420 | |||
421 | /* called by the kernel-interface routine "zft_write()" | ||
422 | */ | ||
423 | int _zft_write(const char __user *buff, int req_len) | ||
424 | { | ||
425 | int result = 0; | ||
426 | int written = 0; | ||
427 | int write_cnt; | ||
428 | int seg_sz; | ||
429 | static const zft_volinfo *volume = NULL; | ||
430 | TRACE_FUN(ft_t_flow); | ||
431 | |||
432 | zft_resid = req_len; | ||
433 | last_write_failed = 1; /* reset to 0 when successful */ | ||
434 | /* check if write is allowed | ||
435 | */ | ||
436 | TRACE_CATCH(check_write_access(req_len, &volume,&zft_pos,zft_blk_sz),); | ||
437 | while (req_len > 0) { | ||
438 | /* Allow us to escape from this loop with a signal ! | ||
439 | */ | ||
440 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
441 | seg_sz = zft_get_seg_sz(zft_pos.seg_pos); | ||
442 | if ((write_cnt = fill_deblock_buf(zft_deblock_buf, | ||
443 | seg_sz, | ||
444 | &zft_pos, | ||
445 | volume, | ||
446 | buff, | ||
447 | req_len)) < 0) { | ||
448 | zft_resid -= written; | ||
449 | if (write_cnt == -ENOSPC) { | ||
450 | /* leave the remainder to flush_buffers() | ||
451 | */ | ||
452 | TRACE(ft_t_info, "No space left on device"); | ||
453 | last_write_failed = 0; | ||
454 | if (!need_flush) { | ||
455 | need_flush = written > 0; | ||
456 | } | ||
457 | TRACE_EXIT written > 0 ? written : -ENOSPC; | ||
458 | } else { | ||
459 | TRACE_EXIT result; | ||
460 | } | ||
461 | } | ||
462 | if (zft_pos.seg_byte_pos == seg_sz) { | ||
463 | TRACE_CATCH(ftape_write_segment(zft_pos.seg_pos, | ||
464 | zft_deblock_buf, | ||
465 | FT_WR_ASYNC), | ||
466 | zft_resid -= written); | ||
467 | zft_written_segments ++; | ||
468 | zft_pos.seg_byte_pos = 0; | ||
469 | zft_deblock_segment = zft_pos.seg_pos; | ||
470 | ++zft_pos.seg_pos; | ||
471 | } | ||
472 | written += write_cnt; | ||
473 | buff += write_cnt; | ||
474 | req_len -= write_cnt; | ||
475 | } /* while (req_len > 0) */ | ||
476 | TRACE(ft_t_data_flow, "remaining in blocking buffer: %d", | ||
477 | zft_pos.seg_byte_pos); | ||
478 | TRACE(ft_t_data_flow, "just written bytes: %d", written); | ||
479 | last_write_failed = 0; | ||
480 | zft_resid -= written; | ||
481 | need_flush = need_flush || written > 0; | ||
482 | TRACE_EXIT written; /* bytes written */ | ||
483 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-write.h b/drivers/char/ftape/zftape/zftape-write.h deleted file mode 100644 index ea887015b493..000000000000 --- a/drivers/char/ftape/zftape/zftape-write.h +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_WRITE_H | ||
2 | #define _ZFTAPE_WRITE_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/zftape/zftape-write.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:13 $ | ||
25 | * | ||
26 | * This file contains the definitions for the write functions | ||
27 | * for the zftape driver for Linux. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | extern int zft_flush_buffers(void); | ||
32 | extern int zft_update_header_segments(void); | ||
33 | extern void zft_prevent_flush(void); | ||
34 | |||
35 | /* hook for the VFS interface | ||
36 | */ | ||
37 | extern int _zft_write(const char __user *buff, int req_len); | ||
38 | #endif /* _ZFTAPE_WRITE_H */ | ||
diff --git a/drivers/char/ftape/zftape/zftape_syms.c b/drivers/char/ftape/zftape/zftape_syms.c deleted file mode 100644 index 2db1401682df..000000000000 --- a/drivers/char/ftape/zftape/zftape_syms.c +++ /dev/null | |||
@@ -1,43 +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/zftape/zftape_syms.c,v $ | ||
20 | * $Revision: 1.3 $ | ||
21 | * $Date: 1997/10/05 19:19:14 $ | ||
22 | * | ||
23 | * This file contains the symbols that the zftape frontend to | ||
24 | * the ftape floppy tape driver exports | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | |||
29 | #include <linux/zftape.h> | ||
30 | |||
31 | #include "../zftape/zftape-init.h" | ||
32 | #include "../zftape/zftape-read.h" | ||
33 | #include "../zftape/zftape-buffers.h" | ||
34 | #include "../zftape/zftape-ctl.h" | ||
35 | |||
36 | /* zftape-init.c */ | ||
37 | EXPORT_SYMBOL(zft_cmpr_register); | ||
38 | /* zftape-read.c */ | ||
39 | EXPORT_SYMBOL(zft_fetch_segment_fraction); | ||
40 | /* zftape-buffers.c */ | ||
41 | EXPORT_SYMBOL(zft_vmalloc_once); | ||
42 | EXPORT_SYMBOL(zft_vmalloc_always); | ||
43 | EXPORT_SYMBOL(zft_vfree); | ||
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 4d59ece67292..ef671739cfea 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c | |||
@@ -3013,6 +3013,11 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, | |||
3013 | #endif | 3013 | #endif |
3014 | 3014 | ||
3015 | err = -ENODEV; | 3015 | err = -ENODEV; |
3016 | |||
3017 | if (pci_enable_device(pdev)) | ||
3018 | goto err_out; | ||
3019 | pci_set_master(pdev); | ||
3020 | |||
3016 | if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) { | 3021 | if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) { |
3017 | qp = quattro_pci_find(pdev); | 3022 | qp = quattro_pci_find(pdev); |
3018 | if (qp == NULL) | 3023 | if (qp == NULL) |
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 79ffef6bfaf8..a2cef57d7bcb 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -1264,15 +1264,21 @@ __dasd_check_expire(struct dasd_device * device) | |||
1264 | if (list_empty(&device->ccw_queue)) | 1264 | if (list_empty(&device->ccw_queue)) |
1265 | return; | 1265 | return; |
1266 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); | 1266 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); |
1267 | if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) { | 1267 | if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) && |
1268 | if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) { | 1268 | (time_after_eq(jiffies, cqr->expires + cqr->starttime))) { |
1269 | if (device->discipline->term_IO(cqr) != 0) { | ||
1270 | /* Hmpf, try again in 5 sec */ | ||
1271 | dasd_set_timer(device, 5*HZ); | ||
1272 | DEV_MESSAGE(KERN_ERR, device, | ||
1273 | "internal error - timeout (%is) expired " | ||
1274 | "for cqr %p, termination failed, " | ||
1275 | "retrying in 5s", | ||
1276 | (cqr->expires/HZ), cqr); | ||
1277 | } else { | ||
1269 | DEV_MESSAGE(KERN_ERR, device, | 1278 | DEV_MESSAGE(KERN_ERR, device, |
1270 | "internal error - timeout (%is) expired " | 1279 | "internal error - timeout (%is) expired " |
1271 | "for cqr %p (%i retries left)", | 1280 | "for cqr %p (%i retries left)", |
1272 | (cqr->expires/HZ), cqr, cqr->retries); | 1281 | (cqr->expires/HZ), cqr, cqr->retries); |
1273 | if (device->discipline->term_IO(cqr) != 0) | ||
1274 | /* Hmpf, try again in 1/10 sec */ | ||
1275 | dasd_set_timer(device, 10); | ||
1276 | } | 1282 | } |
1277 | } | 1283 | } |
1278 | } | 1284 | } |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 91cf971f0652..17fdd8c9f740 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -684,21 +684,26 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, | |||
684 | const char *buf, size_t count) | 684 | const char *buf, size_t count) |
685 | { | 685 | { |
686 | struct dasd_devmap *devmap; | 686 | struct dasd_devmap *devmap; |
687 | int ro_flag; | 687 | int val; |
688 | char *endp; | ||
688 | 689 | ||
689 | devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); | 690 | devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); |
690 | if (IS_ERR(devmap)) | 691 | if (IS_ERR(devmap)) |
691 | return PTR_ERR(devmap); | 692 | return PTR_ERR(devmap); |
692 | ro_flag = buf[0] == '1'; | 693 | |
694 | val = simple_strtoul(buf, &endp, 0); | ||
695 | if (((endp + 1) < (buf + count)) || (val > 1)) | ||
696 | return -EINVAL; | ||
697 | |||
693 | spin_lock(&dasd_devmap_lock); | 698 | spin_lock(&dasd_devmap_lock); |
694 | if (ro_flag) | 699 | if (val) |
695 | devmap->features |= DASD_FEATURE_READONLY; | 700 | devmap->features |= DASD_FEATURE_READONLY; |
696 | else | 701 | else |
697 | devmap->features &= ~DASD_FEATURE_READONLY; | 702 | devmap->features &= ~DASD_FEATURE_READONLY; |
698 | if (devmap->device) | 703 | if (devmap->device) |
699 | devmap->device->features = devmap->features; | 704 | devmap->device->features = devmap->features; |
700 | if (devmap->device && devmap->device->gdp) | 705 | if (devmap->device && devmap->device->gdp) |
701 | set_disk_ro(devmap->device->gdp, ro_flag); | 706 | set_disk_ro(devmap->device->gdp, val); |
702 | spin_unlock(&dasd_devmap_lock); | 707 | spin_unlock(&dasd_devmap_lock); |
703 | return count; | 708 | return count; |
704 | } | 709 | } |
@@ -729,17 +734,22 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, | |||
729 | { | 734 | { |
730 | struct dasd_devmap *devmap; | 735 | struct dasd_devmap *devmap; |
731 | ssize_t rc; | 736 | ssize_t rc; |
732 | int use_diag; | 737 | int val; |
738 | char *endp; | ||
733 | 739 | ||
734 | devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); | 740 | devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); |
735 | if (IS_ERR(devmap)) | 741 | if (IS_ERR(devmap)) |
736 | return PTR_ERR(devmap); | 742 | return PTR_ERR(devmap); |
737 | use_diag = buf[0] == '1'; | 743 | |
744 | val = simple_strtoul(buf, &endp, 0); | ||
745 | if (((endp + 1) < (buf + count)) || (val > 1)) | ||
746 | return -EINVAL; | ||
747 | |||
738 | spin_lock(&dasd_devmap_lock); | 748 | spin_lock(&dasd_devmap_lock); |
739 | /* Changing diag discipline flag is only allowed in offline state. */ | 749 | /* Changing diag discipline flag is only allowed in offline state. */ |
740 | rc = count; | 750 | rc = count; |
741 | if (!devmap->device) { | 751 | if (!devmap->device) { |
742 | if (use_diag) | 752 | if (val) |
743 | devmap->features |= DASD_FEATURE_USEDIAG; | 753 | devmap->features |= DASD_FEATURE_USEDIAG; |
744 | else | 754 | else |
745 | devmap->features &= ~DASD_FEATURE_USEDIAG; | 755 | devmap->features &= ~DASD_FEATURE_USEDIAG; |
@@ -854,14 +864,20 @@ dasd_eer_store(struct device *dev, struct device_attribute *attr, | |||
854 | const char *buf, size_t count) | 864 | const char *buf, size_t count) |
855 | { | 865 | { |
856 | struct dasd_devmap *devmap; | 866 | struct dasd_devmap *devmap; |
857 | int rc; | 867 | int val, rc; |
868 | char *endp; | ||
858 | 869 | ||
859 | devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); | 870 | devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); |
860 | if (IS_ERR(devmap)) | 871 | if (IS_ERR(devmap)) |
861 | return PTR_ERR(devmap); | 872 | return PTR_ERR(devmap); |
862 | if (!devmap->device) | 873 | if (!devmap->device) |
863 | return count; | 874 | return -ENODEV; |
864 | if (buf[0] == '1') { | 875 | |
876 | val = simple_strtoul(buf, &endp, 0); | ||
877 | if (((endp + 1) < (buf + count)) || (val > 1)) | ||
878 | return -EINVAL; | ||
879 | |||
880 | if (val) { | ||
865 | rc = dasd_eer_enable(devmap->device); | 881 | rc = dasd_eer_enable(devmap->device); |
866 | if (rc) | 882 | if (rc) |
867 | return rc; | 883 | return rc; |
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index d7de175d53f0..c9321b920e90 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
@@ -299,14 +299,14 @@ raw3215_timeout(unsigned long __data) | |||
299 | struct raw3215_info *raw = (struct raw3215_info *) __data; | 299 | struct raw3215_info *raw = (struct raw3215_info *) __data; |
300 | unsigned long flags; | 300 | unsigned long flags; |
301 | 301 | ||
302 | spin_lock_irqsave(raw->lock, flags); | 302 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
303 | if (raw->flags & RAW3215_TIMER_RUNS) { | 303 | if (raw->flags & RAW3215_TIMER_RUNS) { |
304 | del_timer(&raw->timer); | 304 | del_timer(&raw->timer); |
305 | raw->flags &= ~RAW3215_TIMER_RUNS; | 305 | raw->flags &= ~RAW3215_TIMER_RUNS; |
306 | raw3215_mk_write_req(raw); | 306 | raw3215_mk_write_req(raw); |
307 | raw3215_start_io(raw); | 307 | raw3215_start_io(raw); |
308 | } | 308 | } |
309 | spin_unlock_irqrestore(raw->lock, flags); | 309 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
310 | } | 310 | } |
311 | 311 | ||
312 | /* | 312 | /* |
@@ -355,10 +355,10 @@ raw3215_tasklet(void *data) | |||
355 | unsigned long flags; | 355 | unsigned long flags; |
356 | 356 | ||
357 | raw = (struct raw3215_info *) data; | 357 | raw = (struct raw3215_info *) data; |
358 | spin_lock_irqsave(raw->lock, flags); | 358 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
359 | raw3215_mk_write_req(raw); | 359 | raw3215_mk_write_req(raw); |
360 | raw3215_try_io(raw); | 360 | raw3215_try_io(raw); |
361 | spin_unlock_irqrestore(raw->lock, flags); | 361 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
362 | /* Check for pending message from raw3215_irq */ | 362 | /* Check for pending message from raw3215_irq */ |
363 | if (raw->message != NULL) { | 363 | if (raw->message != NULL) { |
364 | printk(raw->message, raw->msg_dstat, raw->msg_cstat); | 364 | printk(raw->message, raw->msg_dstat, raw->msg_cstat); |
@@ -512,9 +512,9 @@ raw3215_make_room(struct raw3215_info *raw, unsigned int length) | |||
512 | if (RAW3215_BUFFER_SIZE - raw->count >= length) | 512 | if (RAW3215_BUFFER_SIZE - raw->count >= length) |
513 | break; | 513 | break; |
514 | /* there might be another cpu waiting for the lock */ | 514 | /* there might be another cpu waiting for the lock */ |
515 | spin_unlock(raw->lock); | 515 | spin_unlock(get_ccwdev_lock(raw->cdev)); |
516 | udelay(100); | 516 | udelay(100); |
517 | spin_lock(raw->lock); | 517 | spin_lock(get_ccwdev_lock(raw->cdev)); |
518 | } | 518 | } |
519 | } | 519 | } |
520 | 520 | ||
@@ -528,7 +528,7 @@ raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) | |||
528 | int c, count; | 528 | int c, count; |
529 | 529 | ||
530 | while (length > 0) { | 530 | while (length > 0) { |
531 | spin_lock_irqsave(raw->lock, flags); | 531 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
532 | count = (length > RAW3215_BUFFER_SIZE) ? | 532 | count = (length > RAW3215_BUFFER_SIZE) ? |
533 | RAW3215_BUFFER_SIZE : length; | 533 | RAW3215_BUFFER_SIZE : length; |
534 | length -= count; | 534 | length -= count; |
@@ -555,7 +555,7 @@ raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) | |||
555 | /* start or queue request */ | 555 | /* start or queue request */ |
556 | raw3215_try_io(raw); | 556 | raw3215_try_io(raw); |
557 | } | 557 | } |
558 | spin_unlock_irqrestore(raw->lock, flags); | 558 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
559 | } | 559 | } |
560 | } | 560 | } |
561 | 561 | ||
@@ -568,7 +568,7 @@ raw3215_putchar(struct raw3215_info *raw, unsigned char ch) | |||
568 | unsigned long flags; | 568 | unsigned long flags; |
569 | unsigned int length, i; | 569 | unsigned int length, i; |
570 | 570 | ||
571 | spin_lock_irqsave(raw->lock, flags); | 571 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
572 | if (ch == '\t') { | 572 | if (ch == '\t') { |
573 | length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE); | 573 | length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE); |
574 | raw->line_pos += length; | 574 | raw->line_pos += length; |
@@ -592,7 +592,7 @@ raw3215_putchar(struct raw3215_info *raw, unsigned char ch) | |||
592 | /* start or queue request */ | 592 | /* start or queue request */ |
593 | raw3215_try_io(raw); | 593 | raw3215_try_io(raw); |
594 | } | 594 | } |
595 | spin_unlock_irqrestore(raw->lock, flags); | 595 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
596 | } | 596 | } |
597 | 597 | ||
598 | /* | 598 | /* |
@@ -604,13 +604,13 @@ raw3215_flush_buffer(struct raw3215_info *raw) | |||
604 | { | 604 | { |
605 | unsigned long flags; | 605 | unsigned long flags; |
606 | 606 | ||
607 | spin_lock_irqsave(raw->lock, flags); | 607 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
608 | if (raw->count > 0) { | 608 | if (raw->count > 0) { |
609 | raw->flags |= RAW3215_FLUSHING; | 609 | raw->flags |= RAW3215_FLUSHING; |
610 | raw3215_try_io(raw); | 610 | raw3215_try_io(raw); |
611 | raw->flags &= ~RAW3215_FLUSHING; | 611 | raw->flags &= ~RAW3215_FLUSHING; |
612 | } | 612 | } |
613 | spin_unlock_irqrestore(raw->lock, flags); | 613 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
614 | } | 614 | } |
615 | 615 | ||
616 | /* | 616 | /* |
@@ -625,9 +625,9 @@ raw3215_startup(struct raw3215_info *raw) | |||
625 | return 0; | 625 | return 0; |
626 | raw->line_pos = 0; | 626 | raw->line_pos = 0; |
627 | raw->flags |= RAW3215_ACTIVE; | 627 | raw->flags |= RAW3215_ACTIVE; |
628 | spin_lock_irqsave(raw->lock, flags); | 628 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
629 | raw3215_try_io(raw); | 629 | raw3215_try_io(raw); |
630 | spin_unlock_irqrestore(raw->lock, flags); | 630 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
631 | 631 | ||
632 | return 0; | 632 | return 0; |
633 | } | 633 | } |
@@ -644,21 +644,21 @@ raw3215_shutdown(struct raw3215_info *raw) | |||
644 | if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED)) | 644 | if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED)) |
645 | return; | 645 | return; |
646 | /* Wait for outstanding requests, then free irq */ | 646 | /* Wait for outstanding requests, then free irq */ |
647 | spin_lock_irqsave(raw->lock, flags); | 647 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
648 | if ((raw->flags & RAW3215_WORKING) || | 648 | if ((raw->flags & RAW3215_WORKING) || |
649 | raw->queued_write != NULL || | 649 | raw->queued_write != NULL || |
650 | raw->queued_read != NULL) { | 650 | raw->queued_read != NULL) { |
651 | raw->flags |= RAW3215_CLOSING; | 651 | raw->flags |= RAW3215_CLOSING; |
652 | add_wait_queue(&raw->empty_wait, &wait); | 652 | add_wait_queue(&raw->empty_wait, &wait); |
653 | set_current_state(TASK_INTERRUPTIBLE); | 653 | set_current_state(TASK_INTERRUPTIBLE); |
654 | spin_unlock_irqrestore(raw->lock, flags); | 654 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
655 | schedule(); | 655 | schedule(); |
656 | spin_lock_irqsave(raw->lock, flags); | 656 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
657 | remove_wait_queue(&raw->empty_wait, &wait); | 657 | remove_wait_queue(&raw->empty_wait, &wait); |
658 | set_current_state(TASK_RUNNING); | 658 | set_current_state(TASK_RUNNING); |
659 | raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING); | 659 | raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING); |
660 | } | 660 | } |
661 | spin_unlock_irqrestore(raw->lock, flags); | 661 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
662 | } | 662 | } |
663 | 663 | ||
664 | static int | 664 | static int |
@@ -686,7 +686,6 @@ raw3215_probe (struct ccw_device *cdev) | |||
686 | } | 686 | } |
687 | 687 | ||
688 | raw->cdev = cdev; | 688 | raw->cdev = cdev; |
689 | raw->lock = get_ccwdev_lock(cdev); | ||
690 | raw->inbuf = (char *) raw + sizeof(struct raw3215_info); | 689 | raw->inbuf = (char *) raw + sizeof(struct raw3215_info); |
691 | memset(raw, 0, sizeof(struct raw3215_info)); | 690 | memset(raw, 0, sizeof(struct raw3215_info)); |
692 | raw->buffer = (char *) kmalloc(RAW3215_BUFFER_SIZE, | 691 | raw->buffer = (char *) kmalloc(RAW3215_BUFFER_SIZE, |
@@ -809,9 +808,9 @@ con3215_unblank(void) | |||
809 | unsigned long flags; | 808 | unsigned long flags; |
810 | 809 | ||
811 | raw = raw3215[0]; /* console 3215 is the first one */ | 810 | raw = raw3215[0]; /* console 3215 is the first one */ |
812 | spin_lock_irqsave(raw->lock, flags); | 811 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
813 | raw3215_make_room(raw, RAW3215_BUFFER_SIZE); | 812 | raw3215_make_room(raw, RAW3215_BUFFER_SIZE); |
814 | spin_unlock_irqrestore(raw->lock, flags); | 813 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
815 | } | 814 | } |
816 | 815 | ||
817 | static int __init | 816 | static int __init |
@@ -873,7 +872,6 @@ con3215_init(void) | |||
873 | raw->buffer = (char *) alloc_bootmem_low(RAW3215_BUFFER_SIZE); | 872 | raw->buffer = (char *) alloc_bootmem_low(RAW3215_BUFFER_SIZE); |
874 | raw->inbuf = (char *) alloc_bootmem_low(RAW3215_INBUF_SIZE); | 873 | raw->inbuf = (char *) alloc_bootmem_low(RAW3215_INBUF_SIZE); |
875 | raw->cdev = cdev; | 874 | raw->cdev = cdev; |
876 | raw->lock = get_ccwdev_lock(cdev); | ||
877 | cdev->dev.driver_data = raw; | 875 | cdev->dev.driver_data = raw; |
878 | cdev->handler = raw3215_irq; | 876 | cdev->handler = raw3215_irq; |
879 | 877 | ||
@@ -1066,10 +1064,10 @@ tty3215_unthrottle(struct tty_struct * tty) | |||
1066 | 1064 | ||
1067 | raw = (struct raw3215_info *) tty->driver_data; | 1065 | raw = (struct raw3215_info *) tty->driver_data; |
1068 | if (raw->flags & RAW3215_THROTTLED) { | 1066 | if (raw->flags & RAW3215_THROTTLED) { |
1069 | spin_lock_irqsave(raw->lock, flags); | 1067 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
1070 | raw->flags &= ~RAW3215_THROTTLED; | 1068 | raw->flags &= ~RAW3215_THROTTLED; |
1071 | raw3215_try_io(raw); | 1069 | raw3215_try_io(raw); |
1072 | spin_unlock_irqrestore(raw->lock, flags); | 1070 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
1073 | } | 1071 | } |
1074 | } | 1072 | } |
1075 | 1073 | ||
@@ -1096,10 +1094,10 @@ tty3215_start(struct tty_struct *tty) | |||
1096 | 1094 | ||
1097 | raw = (struct raw3215_info *) tty->driver_data; | 1095 | raw = (struct raw3215_info *) tty->driver_data; |
1098 | if (raw->flags & RAW3215_STOPPED) { | 1096 | if (raw->flags & RAW3215_STOPPED) { |
1099 | spin_lock_irqsave(raw->lock, flags); | 1097 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
1100 | raw->flags &= ~RAW3215_STOPPED; | 1098 | raw->flags &= ~RAW3215_STOPPED; |
1101 | raw3215_try_io(raw); | 1099 | raw3215_try_io(raw); |
1102 | spin_unlock_irqrestore(raw->lock, flags); | 1100 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
1103 | } | 1101 | } |
1104 | } | 1102 | } |
1105 | 1103 | ||
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c index 32004aae95c1..ffa9282ce97a 100644 --- a/drivers/s390/char/sclp_quiesce.c +++ b/drivers/s390/char/sclp_quiesce.c | |||
@@ -19,52 +19,17 @@ | |||
19 | 19 | ||
20 | #include "sclp.h" | 20 | #include "sclp.h" |
21 | 21 | ||
22 | |||
23 | #ifdef CONFIG_SMP | ||
24 | /* Signal completion of shutdown process. All CPUs except the first to enter | ||
25 | * this function: go to stopped state. First CPU: wait until all other | ||
26 | * CPUs are in stopped or check stop state. Afterwards, load special PSW | ||
27 | * to indicate completion. */ | ||
28 | static void | ||
29 | do_load_quiesce_psw(void * __unused) | ||
30 | { | ||
31 | static atomic_t cpuid = ATOMIC_INIT(-1); | ||
32 | psw_t quiesce_psw; | ||
33 | int cpu; | ||
34 | |||
35 | if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1) | ||
36 | signal_processor(smp_processor_id(), sigp_stop); | ||
37 | /* Wait for all other cpus to enter stopped state */ | ||
38 | for_each_online_cpu(cpu) { | ||
39 | if (cpu == smp_processor_id()) | ||
40 | continue; | ||
41 | while(!smp_cpu_not_running(cpu)) | ||
42 | cpu_relax(); | ||
43 | } | ||
44 | /* Quiesce the last cpu with the special psw */ | ||
45 | quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; | ||
46 | quiesce_psw.addr = 0xfff; | ||
47 | __load_psw(quiesce_psw); | ||
48 | } | ||
49 | |||
50 | /* Shutdown handler. Perform shutdown function on all CPUs. */ | ||
51 | static void | ||
52 | do_machine_quiesce(void) | ||
53 | { | ||
54 | on_each_cpu(do_load_quiesce_psw, NULL, 0, 0); | ||
55 | } | ||
56 | #else | ||
57 | /* Shutdown handler. Signal completion of shutdown by loading special PSW. */ | 22 | /* Shutdown handler. Signal completion of shutdown by loading special PSW. */ |
58 | static void | 23 | static void |
59 | do_machine_quiesce(void) | 24 | do_machine_quiesce(void) |
60 | { | 25 | { |
61 | psw_t quiesce_psw; | 26 | psw_t quiesce_psw; |
62 | 27 | ||
28 | smp_send_stop(); | ||
63 | quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; | 29 | quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; |
64 | quiesce_psw.addr = 0xfff; | 30 | quiesce_psw.addr = 0xfff; |
65 | __load_psw(quiesce_psw); | 31 | __load_psw(quiesce_psw); |
66 | } | 32 | } |
67 | #endif | ||
68 | 33 | ||
69 | /* Handler for quiesce event. Start shutdown procedure. */ | 34 | /* Handler for quiesce event. Start shutdown procedure. */ |
70 | static void | 35 | static void |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 2d78f0f4a40f..dbfb77b03928 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -251,6 +251,8 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) | |||
251 | cc = cio_clear(sch); | 251 | cc = cio_clear(sch); |
252 | if (cc == -ENODEV) | 252 | if (cc == -ENODEV) |
253 | goto out_unreg; | 253 | goto out_unreg; |
254 | /* Request retry of internal operation. */ | ||
255 | device_set_intretry(sch); | ||
254 | /* Call handler. */ | 256 | /* Call handler. */ |
255 | if (sch->driver && sch->driver->termination) | 257 | if (sch->driver && sch->driver->termination) |
256 | sch->driver->termination(&sch->dev); | 258 | sch->driver->termination(&sch->dev); |
@@ -711,9 +713,6 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index) | |||
711 | { | 713 | { |
712 | int cc; | 714 | int cc; |
713 | 715 | ||
714 | if (!device_is_online(sch)) | ||
715 | /* cio could be doing I/O. */ | ||
716 | return 0; | ||
717 | cc = stsch(sch->schid, &sch->schib); | 716 | cc = stsch(sch->schid, &sch->schib); |
718 | if (cc) | 717 | if (cc) |
719 | return 0; | 718 | return 0; |
@@ -722,6 +721,26 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index) | |||
722 | return 0; | 721 | return 0; |
723 | } | 722 | } |
724 | 723 | ||
724 | static void terminate_internal_io(struct subchannel *sch) | ||
725 | { | ||
726 | if (cio_clear(sch)) { | ||
727 | /* Recheck device in case clear failed. */ | ||
728 | sch->lpm = 0; | ||
729 | if (device_trigger_verify(sch) != 0) { | ||
730 | if(css_enqueue_subchannel_slow(sch->schid)) { | ||
731 | css_clear_subchannel_slow_list(); | ||
732 | need_rescan = 1; | ||
733 | } | ||
734 | } | ||
735 | return; | ||
736 | } | ||
737 | /* Request retry of internal operation. */ | ||
738 | device_set_intretry(sch); | ||
739 | /* Call handler. */ | ||
740 | if (sch->driver && sch->driver->termination) | ||
741 | sch->driver->termination(&sch->dev); | ||
742 | } | ||
743 | |||
725 | static inline void | 744 | static inline void |
726 | __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) | 745 | __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) |
727 | { | 746 | { |
@@ -744,20 +763,26 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) | |||
744 | device_trigger_reprobe(sch); | 763 | device_trigger_reprobe(sch); |
745 | else if (sch->driver && sch->driver->verify) | 764 | else if (sch->driver && sch->driver->verify) |
746 | sch->driver->verify(&sch->dev); | 765 | sch->driver->verify(&sch->dev); |
747 | } else { | 766 | break; |
748 | sch->opm &= ~(0x80 >> chp); | 767 | } |
749 | sch->lpm &= ~(0x80 >> chp); | 768 | sch->opm &= ~(0x80 >> chp); |
750 | if (check_for_io_on_path(sch, chp)) | 769 | sch->lpm &= ~(0x80 >> chp); |
770 | if (check_for_io_on_path(sch, chp)) { | ||
771 | if (device_is_online(sch)) | ||
751 | /* Path verification is done after killing. */ | 772 | /* Path verification is done after killing. */ |
752 | device_kill_io(sch); | 773 | device_kill_io(sch); |
753 | else if (!sch->lpm) { | 774 | else |
775 | /* Kill and retry internal I/O. */ | ||
776 | terminate_internal_io(sch); | ||
777 | } else if (!sch->lpm) { | ||
778 | if (device_trigger_verify(sch) != 0) { | ||
754 | if (css_enqueue_subchannel_slow(sch->schid)) { | 779 | if (css_enqueue_subchannel_slow(sch->schid)) { |
755 | css_clear_subchannel_slow_list(); | 780 | css_clear_subchannel_slow_list(); |
756 | need_rescan = 1; | 781 | need_rescan = 1; |
757 | } | 782 | } |
758 | } else if (sch->driver && sch->driver->verify) | 783 | } |
759 | sch->driver->verify(&sch->dev); | 784 | } else if (sch->driver && sch->driver->verify) |
760 | } | 785 | sch->driver->verify(&sch->dev); |
761 | break; | 786 | break; |
762 | } | 787 | } |
763 | spin_unlock_irqrestore(&sch->lock, flags); | 788 | spin_unlock_irqrestore(&sch->lock, flags); |
@@ -1465,41 +1490,6 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no) | |||
1465 | return desc; | 1490 | return desc; |
1466 | } | 1491 | } |
1467 | 1492 | ||
1468 | static int reset_channel_path(struct channel_path *chp) | ||
1469 | { | ||
1470 | int cc; | ||
1471 | |||
1472 | cc = rchp(chp->id); | ||
1473 | switch (cc) { | ||
1474 | case 0: | ||
1475 | return 0; | ||
1476 | case 2: | ||
1477 | return -EBUSY; | ||
1478 | default: | ||
1479 | return -ENODEV; | ||
1480 | } | ||
1481 | } | ||
1482 | |||
1483 | static void reset_channel_paths_css(struct channel_subsystem *css) | ||
1484 | { | ||
1485 | int i; | ||
1486 | |||
1487 | for (i = 0; i <= __MAX_CHPID; i++) { | ||
1488 | if (css->chps[i]) | ||
1489 | reset_channel_path(css->chps[i]); | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | void cio_reset_channel_paths(void) | ||
1494 | { | ||
1495 | int i; | ||
1496 | |||
1497 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
1498 | if (css[i] && css[i]->valid) | ||
1499 | reset_channel_paths_css(css[i]); | ||
1500 | } | ||
1501 | } | ||
1502 | |||
1503 | static int __init | 1493 | static int __init |
1504 | chsc_alloc_sei_area(void) | 1494 | chsc_alloc_sei_area(void) |
1505 | { | 1495 | { |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 8936e460a807..20aee2783847 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/irq.h> | 21 | #include <asm/irq.h> |
22 | #include <asm/irq_regs.h> | 22 | #include <asm/irq_regs.h> |
23 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
24 | #include <asm/reset.h> | ||
24 | #include "airq.h" | 25 | #include "airq.h" |
25 | #include "cio.h" | 26 | #include "cio.h" |
26 | #include "css.h" | 27 | #include "css.h" |
@@ -28,6 +29,7 @@ | |||
28 | #include "ioasm.h" | 29 | #include "ioasm.h" |
29 | #include "blacklist.h" | 30 | #include "blacklist.h" |
30 | #include "cio_debug.h" | 31 | #include "cio_debug.h" |
32 | #include "../s390mach.h" | ||
31 | 33 | ||
32 | debug_info_t *cio_debug_msg_id; | 34 | debug_info_t *cio_debug_msg_id; |
33 | debug_info_t *cio_debug_trace_id; | 35 | debug_info_t *cio_debug_trace_id; |
@@ -841,26 +843,12 @@ __clear_subchannel_easy(struct subchannel_id schid) | |||
841 | return -EBUSY; | 843 | return -EBUSY; |
842 | } | 844 | } |
843 | 845 | ||
844 | struct sch_match_id { | 846 | static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) |
845 | struct subchannel_id schid; | ||
846 | struct ccw_dev_id devid; | ||
847 | int rc; | ||
848 | }; | ||
849 | |||
850 | static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid, | ||
851 | void *data) | ||
852 | { | 847 | { |
853 | struct schib schib; | 848 | struct schib schib; |
854 | struct sch_match_id *match_id = data; | ||
855 | 849 | ||
856 | if (stsch_err(schid, &schib)) | 850 | if (stsch_err(schid, &schib)) |
857 | return -ENXIO; | 851 | return -ENXIO; |
858 | if (match_id && schib.pmcw.dnv && | ||
859 | (schib.pmcw.dev == match_id->devid.devno) && | ||
860 | (schid.ssid == match_id->devid.ssid)) { | ||
861 | match_id->schid = schid; | ||
862 | match_id->rc = 0; | ||
863 | } | ||
864 | if (!schib.pmcw.ena) | 852 | if (!schib.pmcw.ena) |
865 | return 0; | 853 | return 0; |
866 | switch(__disable_subchannel_easy(schid, &schib)) { | 854 | switch(__disable_subchannel_easy(schid, &schib)) { |
@@ -876,27 +864,111 @@ static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid, | |||
876 | return 0; | 864 | return 0; |
877 | } | 865 | } |
878 | 866 | ||
879 | static int clear_all_subchannels_and_match(struct ccw_dev_id *devid, | 867 | static atomic_t chpid_reset_count; |
880 | struct subchannel_id *schid) | 868 | |
869 | static void s390_reset_chpids_mcck_handler(void) | ||
870 | { | ||
871 | struct crw crw; | ||
872 | struct mci *mci; | ||
873 | |||
874 | /* Check for pending channel report word. */ | ||
875 | mci = (struct mci *)&S390_lowcore.mcck_interruption_code; | ||
876 | if (!mci->cp) | ||
877 | return; | ||
878 | /* Process channel report words. */ | ||
879 | while (stcrw(&crw) == 0) { | ||
880 | /* Check for responses to RCHP. */ | ||
881 | if (crw.slct && crw.rsc == CRW_RSC_CPATH) | ||
882 | atomic_dec(&chpid_reset_count); | ||
883 | } | ||
884 | } | ||
885 | |||
886 | #define RCHP_TIMEOUT (30 * USEC_PER_SEC) | ||
887 | static void css_reset(void) | ||
888 | { | ||
889 | int i, ret; | ||
890 | unsigned long long timeout; | ||
891 | |||
892 | /* Reset subchannels. */ | ||
893 | for_each_subchannel(__shutdown_subchannel_easy, NULL); | ||
894 | /* Reset channel paths. */ | ||
895 | s390_reset_mcck_handler = s390_reset_chpids_mcck_handler; | ||
896 | /* Enable channel report machine checks. */ | ||
897 | __ctl_set_bit(14, 28); | ||
898 | /* Temporarily reenable machine checks. */ | ||
899 | local_mcck_enable(); | ||
900 | for (i = 0; i <= __MAX_CHPID; i++) { | ||
901 | ret = rchp(i); | ||
902 | if ((ret == 0) || (ret == 2)) | ||
903 | /* | ||
904 | * rchp either succeeded, or another rchp is already | ||
905 | * in progress. In either case, we'll get a crw. | ||
906 | */ | ||
907 | atomic_inc(&chpid_reset_count); | ||
908 | } | ||
909 | /* Wait for machine check for all channel paths. */ | ||
910 | timeout = get_clock() + (RCHP_TIMEOUT << 12); | ||
911 | while (atomic_read(&chpid_reset_count) != 0) { | ||
912 | if (get_clock() > timeout) | ||
913 | break; | ||
914 | cpu_relax(); | ||
915 | } | ||
916 | /* Disable machine checks again. */ | ||
917 | local_mcck_disable(); | ||
918 | /* Disable channel report machine checks. */ | ||
919 | __ctl_clear_bit(14, 28); | ||
920 | s390_reset_mcck_handler = NULL; | ||
921 | } | ||
922 | |||
923 | static struct reset_call css_reset_call = { | ||
924 | .fn = css_reset, | ||
925 | }; | ||
926 | |||
927 | static int __init init_css_reset_call(void) | ||
928 | { | ||
929 | atomic_set(&chpid_reset_count, 0); | ||
930 | register_reset_call(&css_reset_call); | ||
931 | return 0; | ||
932 | } | ||
933 | |||
934 | arch_initcall(init_css_reset_call); | ||
935 | |||
936 | struct sch_match_id { | ||
937 | struct subchannel_id schid; | ||
938 | struct ccw_dev_id devid; | ||
939 | int rc; | ||
940 | }; | ||
941 | |||
942 | static int __reipl_subchannel_match(struct subchannel_id schid, void *data) | ||
943 | { | ||
944 | struct schib schib; | ||
945 | struct sch_match_id *match_id = data; | ||
946 | |||
947 | if (stsch_err(schid, &schib)) | ||
948 | return -ENXIO; | ||
949 | if (schib.pmcw.dnv && | ||
950 | (schib.pmcw.dev == match_id->devid.devno) && | ||
951 | (schid.ssid == match_id->devid.ssid)) { | ||
952 | match_id->schid = schid; | ||
953 | match_id->rc = 0; | ||
954 | return 1; | ||
955 | } | ||
956 | return 0; | ||
957 | } | ||
958 | |||
959 | static int reipl_find_schid(struct ccw_dev_id *devid, | ||
960 | struct subchannel_id *schid) | ||
881 | { | 961 | { |
882 | struct sch_match_id match_id; | 962 | struct sch_match_id match_id; |
883 | 963 | ||
884 | match_id.devid = *devid; | 964 | match_id.devid = *devid; |
885 | match_id.rc = -ENODEV; | 965 | match_id.rc = -ENODEV; |
886 | local_irq_disable(); | 966 | for_each_subchannel(__reipl_subchannel_match, &match_id); |
887 | for_each_subchannel(__shutdown_subchannel_easy_and_match, &match_id); | ||
888 | if (match_id.rc == 0) | 967 | if (match_id.rc == 0) |
889 | *schid = match_id.schid; | 968 | *schid = match_id.schid; |
890 | return match_id.rc; | 969 | return match_id.rc; |
891 | } | 970 | } |
892 | 971 | ||
893 | |||
894 | void clear_all_subchannels(void) | ||
895 | { | ||
896 | local_irq_disable(); | ||
897 | for_each_subchannel(__shutdown_subchannel_easy_and_match, NULL); | ||
898 | } | ||
899 | |||
900 | extern void do_reipl_asm(__u32 schid); | 972 | extern void do_reipl_asm(__u32 schid); |
901 | 973 | ||
902 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | 974 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ |
@@ -904,9 +976,9 @@ void reipl_ccw_dev(struct ccw_dev_id *devid) | |||
904 | { | 976 | { |
905 | struct subchannel_id schid; | 977 | struct subchannel_id schid; |
906 | 978 | ||
907 | if (clear_all_subchannels_and_match(devid, &schid)) | 979 | s390_reset_system(); |
980 | if (reipl_find_schid(devid, &schid) != 0) | ||
908 | panic("IPL Device not found\n"); | 981 | panic("IPL Device not found\n"); |
909 | cio_reset_channel_paths(); | ||
910 | do_reipl_asm(*((__u32*)&schid)); | 982 | do_reipl_asm(*((__u32*)&schid)); |
911 | } | 983 | } |
912 | 984 | ||
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 4c2ff8336288..9ff064e71767 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -94,6 +94,7 @@ struct ccw_device_private { | |||
94 | unsigned int donotify:1; /* call notify function */ | 94 | unsigned int donotify:1; /* call notify function */ |
95 | unsigned int recog_done:1; /* dev. recog. complete */ | 95 | unsigned int recog_done:1; /* dev. recog. complete */ |
96 | unsigned int fake_irb:1; /* deliver faked irb */ | 96 | unsigned int fake_irb:1; /* deliver faked irb */ |
97 | unsigned int intretry:1; /* retry internal operation */ | ||
97 | } __attribute__((packed)) flags; | 98 | } __attribute__((packed)) flags; |
98 | unsigned long intparm; /* user interruption parameter */ | 99 | unsigned long intparm; /* user interruption parameter */ |
99 | struct qdio_irq *qdio_data; | 100 | struct qdio_irq *qdio_data; |
@@ -171,6 +172,8 @@ void device_trigger_reprobe(struct subchannel *); | |||
171 | /* Helper functions for vary on/off. */ | 172 | /* Helper functions for vary on/off. */ |
172 | int device_is_online(struct subchannel *); | 173 | int device_is_online(struct subchannel *); |
173 | void device_kill_io(struct subchannel *); | 174 | void device_kill_io(struct subchannel *); |
175 | void device_set_intretry(struct subchannel *sch); | ||
176 | int device_trigger_verify(struct subchannel *sch); | ||
174 | 177 | ||
175 | /* Machine check helper function. */ | 178 | /* Machine check helper function. */ |
176 | void device_kill_pending_timer(struct subchannel *); | 179 | void device_kill_pending_timer(struct subchannel *); |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 39c98f940507..d3d3716ff84b 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -687,8 +687,20 @@ io_subchannel_register(void *data) | |||
687 | cdev = data; | 687 | cdev = data; |
688 | sch = to_subchannel(cdev->dev.parent); | 688 | sch = to_subchannel(cdev->dev.parent); |
689 | 689 | ||
690 | /* | ||
691 | * io_subchannel_register() will also be called after device | ||
692 | * recognition has been done for a boxed device (which will already | ||
693 | * be registered). We need to reprobe since we may now have sense id | ||
694 | * information. | ||
695 | */ | ||
690 | if (klist_node_attached(&cdev->dev.knode_parent)) { | 696 | if (klist_node_attached(&cdev->dev.knode_parent)) { |
691 | bus_rescan_devices(&ccw_bus_type); | 697 | if (!cdev->drv) { |
698 | ret = device_reprobe(&cdev->dev); | ||
699 | if (ret) | ||
700 | /* We can't do much here. */ | ||
701 | dev_info(&cdev->dev, "device_reprobe() returned" | ||
702 | " %d\n", ret); | ||
703 | } | ||
692 | goto out; | 704 | goto out; |
693 | } | 705 | } |
694 | /* make it known to the system */ | 706 | /* make it known to the system */ |
@@ -948,6 +960,9 @@ io_subchannel_ioterm(struct device *dev) | |||
948 | cdev = dev->driver_data; | 960 | cdev = dev->driver_data; |
949 | if (!cdev) | 961 | if (!cdev) |
950 | return; | 962 | return; |
963 | /* Internal I/O will be retried by the interrupt handler. */ | ||
964 | if (cdev->private->flags.intretry) | ||
965 | return; | ||
951 | cdev->private->state = DEV_STATE_CLEAR_VERIFY; | 966 | cdev->private->state = DEV_STATE_CLEAR_VERIFY; |
952 | if (cdev->handler) | 967 | if (cdev->handler) |
953 | cdev->handler(cdev, cdev->private->intparm, | 968 | cdev->handler(cdev, cdev->private->intparm, |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index de3d0857db9f..09c7672eb3f3 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -59,6 +59,27 @@ device_set_disconnected(struct subchannel *sch) | |||
59 | cdev->private->state = DEV_STATE_DISCONNECTED; | 59 | cdev->private->state = DEV_STATE_DISCONNECTED; |
60 | } | 60 | } |
61 | 61 | ||
62 | void device_set_intretry(struct subchannel *sch) | ||
63 | { | ||
64 | struct ccw_device *cdev; | ||
65 | |||
66 | cdev = sch->dev.driver_data; | ||
67 | if (!cdev) | ||
68 | return; | ||
69 | cdev->private->flags.intretry = 1; | ||
70 | } | ||
71 | |||
72 | int device_trigger_verify(struct subchannel *sch) | ||
73 | { | ||
74 | struct ccw_device *cdev; | ||
75 | |||
76 | cdev = sch->dev.driver_data; | ||
77 | if (!cdev || !cdev->online) | ||
78 | return -EINVAL; | ||
79 | dev_fsm_event(cdev, DEV_EVENT_VERIFY); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
62 | /* | 83 | /* |
63 | * Timeout function. It just triggers a DEV_EVENT_TIMEOUT. | 84 | * Timeout function. It just triggers a DEV_EVENT_TIMEOUT. |
64 | */ | 85 | */ |
@@ -893,6 +914,12 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) | |||
893 | * had killed the original request. | 914 | * had killed the original request. |
894 | */ | 915 | */ |
895 | if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { | 916 | if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { |
917 | /* Retry Basic Sense if requested. */ | ||
918 | if (cdev->private->flags.intretry) { | ||
919 | cdev->private->flags.intretry = 0; | ||
920 | ccw_device_do_sense(cdev, irb); | ||
921 | return; | ||
922 | } | ||
896 | cdev->private->flags.dosense = 0; | 923 | cdev->private->flags.dosense = 0; |
897 | memset(&cdev->private->irb, 0, sizeof(struct irb)); | 924 | memset(&cdev->private->irb, 0, sizeof(struct irb)); |
898 | ccw_device_accumulate_irb(cdev, irb); | 925 | ccw_device_accumulate_irb(cdev, irb); |
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index a74785b9e4eb..f17275917fe5 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c | |||
@@ -191,6 +191,8 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) | |||
191 | if ((sch->opm & cdev->private->imask) != 0 && | 191 | if ((sch->opm & cdev->private->imask) != 0 && |
192 | cdev->private->iretry > 0) { | 192 | cdev->private->iretry > 0) { |
193 | cdev->private->iretry--; | 193 | cdev->private->iretry--; |
194 | /* Reset internal retry indication. */ | ||
195 | cdev->private->flags.intretry = 0; | ||
194 | ret = cio_start (sch, cdev->private->iccws, | 196 | ret = cio_start (sch, cdev->private->iccws, |
195 | cdev->private->imask); | 197 | cdev->private->imask); |
196 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ | 198 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ |
@@ -237,8 +239,14 @@ ccw_device_check_sense_id(struct ccw_device *cdev) | |||
237 | return 0; /* Success */ | 239 | return 0; /* Success */ |
238 | } | 240 | } |
239 | /* Check the error cases. */ | 241 | /* Check the error cases. */ |
240 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 242 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
243 | /* Retry Sense ID if requested. */ | ||
244 | if (cdev->private->flags.intretry) { | ||
245 | cdev->private->flags.intretry = 0; | ||
246 | return -EAGAIN; | ||
247 | } | ||
241 | return -ETIME; | 248 | return -ETIME; |
249 | } | ||
242 | if (irb->esw.esw0.erw.cons && (irb->ecw[0] & SNS0_CMD_REJECT)) { | 250 | if (irb->esw.esw0.erw.cons && (irb->ecw[0] & SNS0_CMD_REJECT)) { |
243 | /* | 251 | /* |
244 | * if the device doesn't support the SenseID | 252 | * if the device doesn't support the SenseID |
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 2975ce888c19..cb1879a96818 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -71,6 +71,8 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev) | |||
71 | ccw->cda = (__u32) __pa (&cdev->private->pgid[i]); | 71 | ccw->cda = (__u32) __pa (&cdev->private->pgid[i]); |
72 | if (cdev->private->iretry > 0) { | 72 | if (cdev->private->iretry > 0) { |
73 | cdev->private->iretry--; | 73 | cdev->private->iretry--; |
74 | /* Reset internal retry indication. */ | ||
75 | cdev->private->flags.intretry = 0; | ||
74 | ret = cio_start (sch, cdev->private->iccws, | 76 | ret = cio_start (sch, cdev->private->iccws, |
75 | cdev->private->imask); | 77 | cdev->private->imask); |
76 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ | 78 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ |
@@ -122,8 +124,14 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) | |||
122 | 124 | ||
123 | sch = to_subchannel(cdev->dev.parent); | 125 | sch = to_subchannel(cdev->dev.parent); |
124 | irb = &cdev->private->irb; | 126 | irb = &cdev->private->irb; |
125 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 127 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
128 | /* Retry Sense PGID if requested. */ | ||
129 | if (cdev->private->flags.intretry) { | ||
130 | cdev->private->flags.intretry = 0; | ||
131 | return -EAGAIN; | ||
132 | } | ||
126 | return -ETIME; | 133 | return -ETIME; |
134 | } | ||
127 | if (irb->esw.esw0.erw.cons && | 135 | if (irb->esw.esw0.erw.cons && |
128 | (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) { | 136 | (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) { |
129 | /* | 137 | /* |
@@ -253,6 +261,8 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) | |||
253 | ret = -EACCES; | 261 | ret = -EACCES; |
254 | if (cdev->private->iretry > 0) { | 262 | if (cdev->private->iretry > 0) { |
255 | cdev->private->iretry--; | 263 | cdev->private->iretry--; |
264 | /* Reset internal retry indication. */ | ||
265 | cdev->private->flags.intretry = 0; | ||
256 | ret = cio_start (sch, cdev->private->iccws, | 266 | ret = cio_start (sch, cdev->private->iccws, |
257 | cdev->private->imask); | 267 | cdev->private->imask); |
258 | /* We expect an interrupt in case of success or busy | 268 | /* We expect an interrupt in case of success or busy |
@@ -293,6 +303,8 @@ static int __ccw_device_do_nop(struct ccw_device *cdev) | |||
293 | ret = -EACCES; | 303 | ret = -EACCES; |
294 | if (cdev->private->iretry > 0) { | 304 | if (cdev->private->iretry > 0) { |
295 | cdev->private->iretry--; | 305 | cdev->private->iretry--; |
306 | /* Reset internal retry indication. */ | ||
307 | cdev->private->flags.intretry = 0; | ||
296 | ret = cio_start (sch, cdev->private->iccws, | 308 | ret = cio_start (sch, cdev->private->iccws, |
297 | cdev->private->imask); | 309 | cdev->private->imask); |
298 | /* We expect an interrupt in case of success or busy | 310 | /* We expect an interrupt in case of success or busy |
@@ -321,8 +333,14 @@ __ccw_device_check_pgid(struct ccw_device *cdev) | |||
321 | 333 | ||
322 | sch = to_subchannel(cdev->dev.parent); | 334 | sch = to_subchannel(cdev->dev.parent); |
323 | irb = &cdev->private->irb; | 335 | irb = &cdev->private->irb; |
324 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 336 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
337 | /* Retry Set PGID if requested. */ | ||
338 | if (cdev->private->flags.intretry) { | ||
339 | cdev->private->flags.intretry = 0; | ||
340 | return -EAGAIN; | ||
341 | } | ||
325 | return -ETIME; | 342 | return -ETIME; |
343 | } | ||
326 | if (irb->esw.esw0.erw.cons) { | 344 | if (irb->esw.esw0.erw.cons) { |
327 | if (irb->ecw[0] & SNS0_CMD_REJECT) | 345 | if (irb->ecw[0] & SNS0_CMD_REJECT) |
328 | return -EOPNOTSUPP; | 346 | return -EOPNOTSUPP; |
@@ -360,8 +378,14 @@ static int __ccw_device_check_nop(struct ccw_device *cdev) | |||
360 | 378 | ||
361 | sch = to_subchannel(cdev->dev.parent); | 379 | sch = to_subchannel(cdev->dev.parent); |
362 | irb = &cdev->private->irb; | 380 | irb = &cdev->private->irb; |
363 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 381 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
382 | /* Retry NOP if requested. */ | ||
383 | if (cdev->private->flags.intretry) { | ||
384 | cdev->private->flags.intretry = 0; | ||
385 | return -EAGAIN; | ||
386 | } | ||
364 | return -ETIME; | 387 | return -ETIME; |
388 | } | ||
365 | if (irb->scsw.cc == 3) { | 389 | if (irb->scsw.cc == 3) { |
366 | CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x," | 390 | CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x," |
367 | " lpm %02X, became 'not operational'\n", | 391 | " lpm %02X, became 'not operational'\n", |
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 3f7cbce4cd87..bdcf930f7beb 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c | |||
@@ -319,6 +319,9 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) | |||
319 | sch->sense_ccw.count = SENSE_MAX_COUNT; | 319 | sch->sense_ccw.count = SENSE_MAX_COUNT; |
320 | sch->sense_ccw.flags = CCW_FLAG_SLI; | 320 | sch->sense_ccw.flags = CCW_FLAG_SLI; |
321 | 321 | ||
322 | /* Reset internal retry indication. */ | ||
323 | cdev->private->flags.intretry = 0; | ||
324 | |||
322 | return cio_start (sch, &sch->sense_ccw, 0xff); | 325 | return cio_start (sch, &sch->sense_ccw, 0xff); |
323 | } | 326 | } |
324 | 327 | ||
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 476aa1da5cbc..8d5fa1b4d11f 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
@@ -481,7 +481,7 @@ qdio_stop_polling(struct qdio_q *q) | |||
481 | unsigned char state = 0; | 481 | unsigned char state = 0; |
482 | struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr; | 482 | struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr; |
483 | 483 | ||
484 | if (!atomic_swap(&q->polling,0)) | 484 | if (!atomic_xchg(&q->polling,0)) |
485 | return 1; | 485 | return 1; |
486 | 486 | ||
487 | QDIO_DBF_TEXT4(0,trace,"stoppoll"); | 487 | QDIO_DBF_TEXT4(0,trace,"stoppoll"); |
@@ -1964,8 +1964,8 @@ qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) | |||
1964 | QDIO_DBF_HEX0(0,sense,irb,QDIO_DBF_SENSE_LEN); | 1964 | QDIO_DBF_HEX0(0,sense,irb,QDIO_DBF_SENSE_LEN); |
1965 | 1965 | ||
1966 | QDIO_PRINT_WARN("sense data available on qdio channel.\n"); | 1966 | QDIO_PRINT_WARN("sense data available on qdio channel.\n"); |
1967 | HEXDUMP16(WARN,"irb: ",irb); | 1967 | QDIO_HEXDUMP16(WARN,"irb: ",irb); |
1968 | HEXDUMP16(WARN,"sense data: ",irb->ecw); | 1968 | QDIO_HEXDUMP16(WARN,"sense data: ",irb->ecw); |
1969 | } | 1969 | } |
1970 | 1970 | ||
1971 | } | 1971 | } |
@@ -3425,7 +3425,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags, | |||
3425 | 3425 | ||
3426 | if ((used_elements+count==QDIO_MAX_BUFFERS_PER_Q)&& | 3426 | if ((used_elements+count==QDIO_MAX_BUFFERS_PER_Q)&& |
3427 | (callflags&QDIO_FLAG_UNDER_INTERRUPT)) | 3427 | (callflags&QDIO_FLAG_UNDER_INTERRUPT)) |
3428 | atomic_swap(&q->polling,0); | 3428 | atomic_xchg(&q->polling,0); |
3429 | 3429 | ||
3430 | if (used_elements) | 3430 | if (used_elements) |
3431 | return; | 3431 | return; |
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 49bb9e371c32..42927c1b7451 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h | |||
@@ -236,7 +236,7 @@ enum qdio_irq_states { | |||
236 | #define QDIO_PRINT_EMERG(x...) do { } while (0) | 236 | #define QDIO_PRINT_EMERG(x...) do { } while (0) |
237 | #endif | 237 | #endif |
238 | 238 | ||
239 | #define HEXDUMP16(importance,header,ptr) \ | 239 | #define QDIO_HEXDUMP16(importance,header,ptr) \ |
240 | QDIO_PRINT_##importance(header "%02x %02x %02x %02x " \ | 240 | QDIO_PRINT_##importance(header "%02x %02x %02x %02x " \ |
241 | "%02x %02x %02x %02x %02x %02x %02x %02x " \ | 241 | "%02x %02x %02x %02x %02x %02x %02x %02x " \ |
242 | "%02x %02x %02x %02x\n",*(((char*)ptr)), \ | 242 | "%02x %02x %02x %02x\n",*(((char*)ptr)), \ |
@@ -429,8 +429,6 @@ struct qdio_perf_stats { | |||
429 | }; | 429 | }; |
430 | #endif /* QDIO_PERFORMANCE_STATS */ | 430 | #endif /* QDIO_PERFORMANCE_STATS */ |
431 | 431 | ||
432 | #define atomic_swap(a,b) xchg((int*)a.counter,b) | ||
433 | |||
434 | /* unlikely as the later the better */ | 432 | /* unlikely as the later the better */ |
435 | #define SYNC_MEMORY if (unlikely(q->siga_sync)) qdio_siga_sync_q(q) | 433 | #define SYNC_MEMORY if (unlikely(q->siga_sync)) qdio_siga_sync_q(q) |
436 | #define SYNC_MEMORY_ALL if (unlikely(q->siga_sync)) \ | 434 | #define SYNC_MEMORY_ALL if (unlikely(q->siga_sync)) \ |
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 79d89c368919..6a54334ffe09 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -431,7 +431,15 @@ static int ap_uevent (struct device *dev, char **envp, int num_envp, | |||
431 | ap_dev->device_type); | 431 | ap_dev->device_type); |
432 | if (buffer_size - length <= 0) | 432 | if (buffer_size - length <= 0) |
433 | return -ENOMEM; | 433 | return -ENOMEM; |
434 | envp[1] = 0; | 434 | buffer += length; |
435 | buffer_size -= length; | ||
436 | /* Add MODALIAS= */ | ||
437 | envp[1] = buffer; | ||
438 | length = scnprintf(buffer, buffer_size, "MODALIAS=ap:t%02X", | ||
439 | ap_dev->device_type); | ||
440 | if (buffer_size - length <= 0) | ||
441 | return -ENOMEM; | ||
442 | envp[2] = NULL; | ||
435 | return 0; | 443 | return 0; |
436 | } | 444 | } |
437 | 445 | ||
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 66a8aec6efa6..08d4e47070bd 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -54,6 +54,8 @@ | |||
54 | #error Cannot compile lcs.c without some net devices switched on. | 54 | #error Cannot compile lcs.c without some net devices switched on. |
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | #define PRINTK_HEADER " lcs: " | ||
58 | |||
57 | /** | 59 | /** |
58 | * initialization string for output | 60 | * initialization string for output |
59 | */ | 61 | */ |
@@ -120,7 +122,7 @@ lcs_alloc_channel(struct lcs_channel *channel) | |||
120 | kzalloc(LCS_IOBUFFERSIZE, GFP_DMA | GFP_KERNEL); | 122 | kzalloc(LCS_IOBUFFERSIZE, GFP_DMA | GFP_KERNEL); |
121 | if (channel->iob[cnt].data == NULL) | 123 | if (channel->iob[cnt].data == NULL) |
122 | break; | 124 | break; |
123 | channel->iob[cnt].state = BUF_STATE_EMPTY; | 125 | channel->iob[cnt].state = LCS_BUF_STATE_EMPTY; |
124 | } | 126 | } |
125 | if (cnt < LCS_NUM_BUFFS) { | 127 | if (cnt < LCS_NUM_BUFFS) { |
126 | /* Not all io buffers could be allocated. */ | 128 | /* Not all io buffers could be allocated. */ |
@@ -236,7 +238,7 @@ lcs_setup_read_ccws(struct lcs_card *card) | |||
236 | ((struct lcs_header *) | 238 | ((struct lcs_header *) |
237 | card->read.iob[cnt].data)->offset = LCS_ILLEGAL_OFFSET; | 239 | card->read.iob[cnt].data)->offset = LCS_ILLEGAL_OFFSET; |
238 | card->read.iob[cnt].callback = lcs_get_frames_cb; | 240 | card->read.iob[cnt].callback = lcs_get_frames_cb; |
239 | card->read.iob[cnt].state = BUF_STATE_READY; | 241 | card->read.iob[cnt].state = LCS_BUF_STATE_READY; |
240 | card->read.iob[cnt].count = LCS_IOBUFFERSIZE; | 242 | card->read.iob[cnt].count = LCS_IOBUFFERSIZE; |
241 | } | 243 | } |
242 | card->read.ccws[0].flags &= ~CCW_FLAG_PCI; | 244 | card->read.ccws[0].flags &= ~CCW_FLAG_PCI; |
@@ -247,7 +249,7 @@ lcs_setup_read_ccws(struct lcs_card *card) | |||
247 | card->read.ccws[LCS_NUM_BUFFS].cda = | 249 | card->read.ccws[LCS_NUM_BUFFS].cda = |
248 | (__u32) __pa(card->read.ccws); | 250 | (__u32) __pa(card->read.ccws); |
249 | /* Setg initial state of the read channel. */ | 251 | /* Setg initial state of the read channel. */ |
250 | card->read.state = CH_STATE_INIT; | 252 | card->read.state = LCS_CH_STATE_INIT; |
251 | 253 | ||
252 | card->read.io_idx = 0; | 254 | card->read.io_idx = 0; |
253 | card->read.buf_idx = 0; | 255 | card->read.buf_idx = 0; |
@@ -294,7 +296,7 @@ lcs_setup_write_ccws(struct lcs_card *card) | |||
294 | card->write.ccws[LCS_NUM_BUFFS].cda = | 296 | card->write.ccws[LCS_NUM_BUFFS].cda = |
295 | (__u32) __pa(card->write.ccws); | 297 | (__u32) __pa(card->write.ccws); |
296 | /* Set initial state of the write channel. */ | 298 | /* Set initial state of the write channel. */ |
297 | card->read.state = CH_STATE_INIT; | 299 | card->read.state = LCS_CH_STATE_INIT; |
298 | 300 | ||
299 | card->write.io_idx = 0; | 301 | card->write.io_idx = 0; |
300 | card->write.buf_idx = 0; | 302 | card->write.buf_idx = 0; |
@@ -496,7 +498,7 @@ lcs_start_channel(struct lcs_channel *channel) | |||
496 | channel->ccws + channel->io_idx, 0, 0, | 498 | channel->ccws + channel->io_idx, 0, 0, |
497 | DOIO_DENY_PREFETCH | DOIO_ALLOW_SUSPEND); | 499 | DOIO_DENY_PREFETCH | DOIO_ALLOW_SUSPEND); |
498 | if (rc == 0) | 500 | if (rc == 0) |
499 | channel->state = CH_STATE_RUNNING; | 501 | channel->state = LCS_CH_STATE_RUNNING; |
500 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | 502 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); |
501 | if (rc) { | 503 | if (rc) { |
502 | LCS_DBF_TEXT_(4,trace,"essh%s", channel->ccwdev->dev.bus_id); | 504 | LCS_DBF_TEXT_(4,trace,"essh%s", channel->ccwdev->dev.bus_id); |
@@ -520,8 +522,8 @@ lcs_clear_channel(struct lcs_channel *channel) | |||
520 | LCS_DBF_TEXT_(4,trace,"ecsc%s", channel->ccwdev->dev.bus_id); | 522 | LCS_DBF_TEXT_(4,trace,"ecsc%s", channel->ccwdev->dev.bus_id); |
521 | return rc; | 523 | return rc; |
522 | } | 524 | } |
523 | wait_event(channel->wait_q, (channel->state == CH_STATE_CLEARED)); | 525 | wait_event(channel->wait_q, (channel->state == LCS_CH_STATE_CLEARED)); |
524 | channel->state = CH_STATE_STOPPED; | 526 | channel->state = LCS_CH_STATE_STOPPED; |
525 | return rc; | 527 | return rc; |
526 | } | 528 | } |
527 | 529 | ||
@@ -535,11 +537,11 @@ lcs_stop_channel(struct lcs_channel *channel) | |||
535 | unsigned long flags; | 537 | unsigned long flags; |
536 | int rc; | 538 | int rc; |
537 | 539 | ||
538 | if (channel->state == CH_STATE_STOPPED) | 540 | if (channel->state == LCS_CH_STATE_STOPPED) |
539 | return 0; | 541 | return 0; |
540 | LCS_DBF_TEXT(4,trace,"haltsch"); | 542 | LCS_DBF_TEXT(4,trace,"haltsch"); |
541 | LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id); | 543 | LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id); |
542 | channel->state = CH_STATE_INIT; | 544 | channel->state = LCS_CH_STATE_INIT; |
543 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | 545 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); |
544 | rc = ccw_device_halt(channel->ccwdev, (addr_t) channel); | 546 | rc = ccw_device_halt(channel->ccwdev, (addr_t) channel); |
545 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | 547 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); |
@@ -548,7 +550,7 @@ lcs_stop_channel(struct lcs_channel *channel) | |||
548 | return rc; | 550 | return rc; |
549 | } | 551 | } |
550 | /* Asynchronous halt initialted. Wait for its completion. */ | 552 | /* Asynchronous halt initialted. Wait for its completion. */ |
551 | wait_event(channel->wait_q, (channel->state == CH_STATE_HALTED)); | 553 | wait_event(channel->wait_q, (channel->state == LCS_CH_STATE_HALTED)); |
552 | lcs_clear_channel(channel); | 554 | lcs_clear_channel(channel); |
553 | return 0; | 555 | return 0; |
554 | } | 556 | } |
@@ -596,8 +598,8 @@ __lcs_get_buffer(struct lcs_channel *channel) | |||
596 | LCS_DBF_TEXT(5, trace, "_getbuff"); | 598 | LCS_DBF_TEXT(5, trace, "_getbuff"); |
597 | index = channel->io_idx; | 599 | index = channel->io_idx; |
598 | do { | 600 | do { |
599 | if (channel->iob[index].state == BUF_STATE_EMPTY) { | 601 | if (channel->iob[index].state == LCS_BUF_STATE_EMPTY) { |
600 | channel->iob[index].state = BUF_STATE_LOCKED; | 602 | channel->iob[index].state = LCS_BUF_STATE_LOCKED; |
601 | return channel->iob + index; | 603 | return channel->iob + index; |
602 | } | 604 | } |
603 | index = (index + 1) & (LCS_NUM_BUFFS - 1); | 605 | index = (index + 1) & (LCS_NUM_BUFFS - 1); |
@@ -626,7 +628,7 @@ __lcs_resume_channel(struct lcs_channel *channel) | |||
626 | { | 628 | { |
627 | int rc; | 629 | int rc; |
628 | 630 | ||
629 | if (channel->state != CH_STATE_SUSPENDED) | 631 | if (channel->state != LCS_CH_STATE_SUSPENDED) |
630 | return 0; | 632 | return 0; |
631 | if (channel->ccws[channel->io_idx].flags & CCW_FLAG_SUSPEND) | 633 | if (channel->ccws[channel->io_idx].flags & CCW_FLAG_SUSPEND) |
632 | return 0; | 634 | return 0; |
@@ -636,7 +638,7 @@ __lcs_resume_channel(struct lcs_channel *channel) | |||
636 | LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id); | 638 | LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id); |
637 | PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc); | 639 | PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc); |
638 | } else | 640 | } else |
639 | channel->state = CH_STATE_RUNNING; | 641 | channel->state = LCS_CH_STATE_RUNNING; |
640 | return rc; | 642 | return rc; |
641 | 643 | ||
642 | } | 644 | } |
@@ -670,10 +672,10 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
670 | int index, rc; | 672 | int index, rc; |
671 | 673 | ||
672 | LCS_DBF_TEXT(5, trace, "rdybuff"); | 674 | LCS_DBF_TEXT(5, trace, "rdybuff"); |
673 | BUG_ON(buffer->state != BUF_STATE_LOCKED && | 675 | BUG_ON(buffer->state != LCS_BUF_STATE_LOCKED && |
674 | buffer->state != BUF_STATE_PROCESSED); | 676 | buffer->state != LCS_BUF_STATE_PROCESSED); |
675 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | 677 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); |
676 | buffer->state = BUF_STATE_READY; | 678 | buffer->state = LCS_BUF_STATE_READY; |
677 | index = buffer - channel->iob; | 679 | index = buffer - channel->iob; |
678 | /* Set length. */ | 680 | /* Set length. */ |
679 | channel->ccws[index].count = buffer->count; | 681 | channel->ccws[index].count = buffer->count; |
@@ -695,8 +697,8 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
695 | int index, prev, next; | 697 | int index, prev, next; |
696 | 698 | ||
697 | LCS_DBF_TEXT(5, trace, "prcsbuff"); | 699 | LCS_DBF_TEXT(5, trace, "prcsbuff"); |
698 | BUG_ON(buffer->state != BUF_STATE_READY); | 700 | BUG_ON(buffer->state != LCS_BUF_STATE_READY); |
699 | buffer->state = BUF_STATE_PROCESSED; | 701 | buffer->state = LCS_BUF_STATE_PROCESSED; |
700 | index = buffer - channel->iob; | 702 | index = buffer - channel->iob; |
701 | prev = (index - 1) & (LCS_NUM_BUFFS - 1); | 703 | prev = (index - 1) & (LCS_NUM_BUFFS - 1); |
702 | next = (index + 1) & (LCS_NUM_BUFFS - 1); | 704 | next = (index + 1) & (LCS_NUM_BUFFS - 1); |
@@ -704,7 +706,7 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
704 | channel->ccws[index].flags |= CCW_FLAG_SUSPEND; | 706 | channel->ccws[index].flags |= CCW_FLAG_SUSPEND; |
705 | channel->ccws[index].flags &= ~CCW_FLAG_PCI; | 707 | channel->ccws[index].flags &= ~CCW_FLAG_PCI; |
706 | /* Check the suspend bit of the previous buffer. */ | 708 | /* Check the suspend bit of the previous buffer. */ |
707 | if (channel->iob[prev].state == BUF_STATE_READY) { | 709 | if (channel->iob[prev].state == LCS_BUF_STATE_READY) { |
708 | /* | 710 | /* |
709 | * Previous buffer is in state ready. It might have | 711 | * Previous buffer is in state ready. It might have |
710 | * happened in lcs_ready_buffer that the suspend bit | 712 | * happened in lcs_ready_buffer that the suspend bit |
@@ -727,10 +729,10 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
727 | unsigned long flags; | 729 | unsigned long flags; |
728 | 730 | ||
729 | LCS_DBF_TEXT(5, trace, "relbuff"); | 731 | LCS_DBF_TEXT(5, trace, "relbuff"); |
730 | BUG_ON(buffer->state != BUF_STATE_LOCKED && | 732 | BUG_ON(buffer->state != LCS_BUF_STATE_LOCKED && |
731 | buffer->state != BUF_STATE_PROCESSED); | 733 | buffer->state != LCS_BUF_STATE_PROCESSED); |
732 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | 734 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); |
733 | buffer->state = BUF_STATE_EMPTY; | 735 | buffer->state = LCS_BUF_STATE_EMPTY; |
734 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | 736 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); |
735 | } | 737 | } |
736 | 738 | ||
@@ -1264,7 +1266,7 @@ lcs_register_mc_addresses(void *data) | |||
1264 | netif_carrier_off(card->dev); | 1266 | netif_carrier_off(card->dev); |
1265 | netif_tx_disable(card->dev); | 1267 | netif_tx_disable(card->dev); |
1266 | wait_event(card->write.wait_q, | 1268 | wait_event(card->write.wait_q, |
1267 | (card->write.state != CH_STATE_RUNNING)); | 1269 | (card->write.state != LCS_CH_STATE_RUNNING)); |
1268 | lcs_fix_multicast_list(card); | 1270 | lcs_fix_multicast_list(card); |
1269 | if (card->state == DEV_STATE_UP) { | 1271 | if (card->state == DEV_STATE_UP) { |
1270 | netif_carrier_on(card->dev); | 1272 | netif_carrier_on(card->dev); |
@@ -1404,7 +1406,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
1404 | } | 1406 | } |
1405 | } | 1407 | } |
1406 | /* How far in the ccw chain have we processed? */ | 1408 | /* How far in the ccw chain have we processed? */ |
1407 | if ((channel->state != CH_STATE_INIT) && | 1409 | if ((channel->state != LCS_CH_STATE_INIT) && |
1408 | (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { | 1410 | (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { |
1409 | index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa) | 1411 | index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa) |
1410 | - channel->ccws; | 1412 | - channel->ccws; |
@@ -1424,20 +1426,20 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
1424 | (irb->scsw.dstat & DEV_STAT_CHN_END) || | 1426 | (irb->scsw.dstat & DEV_STAT_CHN_END) || |
1425 | (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)) | 1427 | (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)) |
1426 | /* Mark channel as stopped. */ | 1428 | /* Mark channel as stopped. */ |
1427 | channel->state = CH_STATE_STOPPED; | 1429 | channel->state = LCS_CH_STATE_STOPPED; |
1428 | else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED) | 1430 | else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED) |
1429 | /* CCW execution stopped on a suspend bit. */ | 1431 | /* CCW execution stopped on a suspend bit. */ |
1430 | channel->state = CH_STATE_SUSPENDED; | 1432 | channel->state = LCS_CH_STATE_SUSPENDED; |
1431 | if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { | 1433 | if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { |
1432 | if (irb->scsw.cc != 0) { | 1434 | if (irb->scsw.cc != 0) { |
1433 | ccw_device_halt(channel->ccwdev, (addr_t) channel); | 1435 | ccw_device_halt(channel->ccwdev, (addr_t) channel); |
1434 | return; | 1436 | return; |
1435 | } | 1437 | } |
1436 | /* The channel has been stopped by halt_IO. */ | 1438 | /* The channel has been stopped by halt_IO. */ |
1437 | channel->state = CH_STATE_HALTED; | 1439 | channel->state = LCS_CH_STATE_HALTED; |
1438 | } | 1440 | } |
1439 | if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { | 1441 | if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { |
1440 | channel->state = CH_STATE_CLEARED; | 1442 | channel->state = LCS_CH_STATE_CLEARED; |
1441 | } | 1443 | } |
1442 | /* Do the rest in the tasklet. */ | 1444 | /* Do the rest in the tasklet. */ |
1443 | tasklet_schedule(&channel->irq_tasklet); | 1445 | tasklet_schedule(&channel->irq_tasklet); |
@@ -1461,7 +1463,7 @@ lcs_tasklet(unsigned long data) | |||
1461 | /* Check for processed buffers. */ | 1463 | /* Check for processed buffers. */ |
1462 | iob = channel->iob; | 1464 | iob = channel->iob; |
1463 | buf_idx = channel->buf_idx; | 1465 | buf_idx = channel->buf_idx; |
1464 | while (iob[buf_idx].state == BUF_STATE_PROCESSED) { | 1466 | while (iob[buf_idx].state == LCS_BUF_STATE_PROCESSED) { |
1465 | /* Do the callback thing. */ | 1467 | /* Do the callback thing. */ |
1466 | if (iob[buf_idx].callback != NULL) | 1468 | if (iob[buf_idx].callback != NULL) |
1467 | iob[buf_idx].callback(channel, iob + buf_idx); | 1469 | iob[buf_idx].callback(channel, iob + buf_idx); |
@@ -1469,12 +1471,12 @@ lcs_tasklet(unsigned long data) | |||
1469 | } | 1471 | } |
1470 | channel->buf_idx = buf_idx; | 1472 | channel->buf_idx = buf_idx; |
1471 | 1473 | ||
1472 | if (channel->state == CH_STATE_STOPPED) | 1474 | if (channel->state == LCS_CH_STATE_STOPPED) |
1473 | // FIXME: what if rc != 0 ?? | 1475 | // FIXME: what if rc != 0 ?? |
1474 | rc = lcs_start_channel(channel); | 1476 | rc = lcs_start_channel(channel); |
1475 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | 1477 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); |
1476 | if (channel->state == CH_STATE_SUSPENDED && | 1478 | if (channel->state == LCS_CH_STATE_SUSPENDED && |
1477 | channel->iob[channel->io_idx].state == BUF_STATE_READY) { | 1479 | channel->iob[channel->io_idx].state == LCS_BUF_STATE_READY) { |
1478 | // FIXME: what if rc != 0 ?? | 1480 | // FIXME: what if rc != 0 ?? |
1479 | rc = __lcs_resume_channel(channel); | 1481 | rc = __lcs_resume_channel(channel); |
1480 | } | 1482 | } |
@@ -1689,8 +1691,8 @@ lcs_detect(struct lcs_card *card) | |||
1689 | card->state = DEV_STATE_UP; | 1691 | card->state = DEV_STATE_UP; |
1690 | } else { | 1692 | } else { |
1691 | card->state = DEV_STATE_DOWN; | 1693 | card->state = DEV_STATE_DOWN; |
1692 | card->write.state = CH_STATE_INIT; | 1694 | card->write.state = LCS_CH_STATE_INIT; |
1693 | card->read.state = CH_STATE_INIT; | 1695 | card->read.state = LCS_CH_STATE_INIT; |
1694 | } | 1696 | } |
1695 | return rc; | 1697 | return rc; |
1696 | } | 1698 | } |
@@ -1705,8 +1707,8 @@ lcs_stopcard(struct lcs_card *card) | |||
1705 | 1707 | ||
1706 | LCS_DBF_TEXT(3, setup, "stopcard"); | 1708 | LCS_DBF_TEXT(3, setup, "stopcard"); |
1707 | 1709 | ||
1708 | if (card->read.state != CH_STATE_STOPPED && | 1710 | if (card->read.state != LCS_CH_STATE_STOPPED && |
1709 | card->write.state != CH_STATE_STOPPED && | 1711 | card->write.state != LCS_CH_STATE_STOPPED && |
1710 | card->state == DEV_STATE_UP) { | 1712 | card->state == DEV_STATE_UP) { |
1711 | lcs_clear_multicast_list(card); | 1713 | lcs_clear_multicast_list(card); |
1712 | rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP); | 1714 | rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP); |
@@ -1871,7 +1873,7 @@ lcs_stop_device(struct net_device *dev) | |||
1871 | netif_tx_disable(dev); | 1873 | netif_tx_disable(dev); |
1872 | dev->flags &= ~IFF_UP; | 1874 | dev->flags &= ~IFF_UP; |
1873 | wait_event(card->write.wait_q, | 1875 | wait_event(card->write.wait_q, |
1874 | (card->write.state != CH_STATE_RUNNING)); | 1876 | (card->write.state != LCS_CH_STATE_RUNNING)); |
1875 | rc = lcs_stopcard(card); | 1877 | rc = lcs_stopcard(card); |
1876 | if (rc) | 1878 | if (rc) |
1877 | PRINT_ERR("Try it again!\n "); | 1879 | PRINT_ERR("Try it again!\n "); |
diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index b5247dc08b57..0e1e4a0a88f0 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h | |||
@@ -23,11 +23,6 @@ do { \ | |||
23 | } while (0) | 23 | } while (0) |
24 | 24 | ||
25 | /** | 25 | /** |
26 | * some more definitions for debug or output stuff | ||
27 | */ | ||
28 | #define PRINTK_HEADER " lcs: " | ||
29 | |||
30 | /** | ||
31 | * sysfs related stuff | 26 | * sysfs related stuff |
32 | */ | 27 | */ |
33 | #define CARD_FROM_DEV(cdev) \ | 28 | #define CARD_FROM_DEV(cdev) \ |
@@ -127,22 +122,22 @@ do { \ | |||
127 | * LCS Buffer states | 122 | * LCS Buffer states |
128 | */ | 123 | */ |
129 | enum lcs_buffer_states { | 124 | enum lcs_buffer_states { |
130 | BUF_STATE_EMPTY, /* buffer is empty */ | 125 | LCS_BUF_STATE_EMPTY, /* buffer is empty */ |
131 | BUF_STATE_LOCKED, /* buffer is locked, don't touch */ | 126 | LCS_BUF_STATE_LOCKED, /* buffer is locked, don't touch */ |
132 | BUF_STATE_READY, /* buffer is ready for read/write */ | 127 | LCS_BUF_STATE_READY, /* buffer is ready for read/write */ |
133 | BUF_STATE_PROCESSED, | 128 | LCS_BUF_STATE_PROCESSED, |
134 | }; | 129 | }; |
135 | 130 | ||
136 | /** | 131 | /** |
137 | * LCS Channel State Machine declarations | 132 | * LCS Channel State Machine declarations |
138 | */ | 133 | */ |
139 | enum lcs_channel_states { | 134 | enum lcs_channel_states { |
140 | CH_STATE_INIT, | 135 | LCS_CH_STATE_INIT, |
141 | CH_STATE_HALTED, | 136 | LCS_CH_STATE_HALTED, |
142 | CH_STATE_STOPPED, | 137 | LCS_CH_STATE_STOPPED, |
143 | CH_STATE_RUNNING, | 138 | LCS_CH_STATE_RUNNING, |
144 | CH_STATE_SUSPENDED, | 139 | LCS_CH_STATE_SUSPENDED, |
145 | CH_STATE_CLEARED, | 140 | LCS_CH_STATE_CLEARED, |
146 | }; | 141 | }; |
147 | 142 | ||
148 | /** | 143 | /** |
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 821383d8cbe7..53c358c7d368 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h | |||
@@ -151,8 +151,6 @@ qeth_hex_dump(unsigned char *buf, size_t len) | |||
151 | #define SENSE_RESETTING_EVENT_BYTE 1 | 151 | #define SENSE_RESETTING_EVENT_BYTE 1 |
152 | #define SENSE_RESETTING_EVENT_FLAG 0x80 | 152 | #define SENSE_RESETTING_EVENT_FLAG 0x80 |
153 | 153 | ||
154 | #define atomic_swap(a,b) xchg((int *)a.counter, b) | ||
155 | |||
156 | /* | 154 | /* |
157 | * Common IO related definitions | 155 | * Common IO related definitions |
158 | */ | 156 | */ |
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 8364d5475ac7..7fdc5272c446 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c | |||
@@ -2982,7 +2982,7 @@ qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) | |||
2982 | */ | 2982 | */ |
2983 | if ((atomic_read(&queue->used_buffers) <= QETH_LOW_WATERMARK_PACK) || | 2983 | if ((atomic_read(&queue->used_buffers) <= QETH_LOW_WATERMARK_PACK) || |
2984 | !atomic_read(&queue->set_pci_flags_count)){ | 2984 | !atomic_read(&queue->set_pci_flags_count)){ |
2985 | if (atomic_swap(&queue->state, QETH_OUT_Q_LOCKED_FLUSH) == | 2985 | if (atomic_xchg(&queue->state, QETH_OUT_Q_LOCKED_FLUSH) == |
2986 | QETH_OUT_Q_UNLOCKED) { | 2986 | QETH_OUT_Q_UNLOCKED) { |
2987 | /* | 2987 | /* |
2988 | * If we get in here, there was no action in | 2988 | * If we get in here, there was no action in |
@@ -3245,7 +3245,7 @@ qeth_free_qdio_buffers(struct qeth_card *card) | |||
3245 | int i, j; | 3245 | int i, j; |
3246 | 3246 | ||
3247 | QETH_DBF_TEXT(trace, 2, "freeqdbf"); | 3247 | QETH_DBF_TEXT(trace, 2, "freeqdbf"); |
3248 | if (atomic_swap(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == | 3248 | if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == |
3249 | QETH_QDIO_UNINITIALIZED) | 3249 | QETH_QDIO_UNINITIALIZED) |
3250 | return; | 3250 | return; |
3251 | kfree(card->qdio.in_q); | 3251 | kfree(card->qdio.in_q); |
@@ -4366,7 +4366,7 @@ out: | |||
4366 | if (flush_count) | 4366 | if (flush_count) |
4367 | qeth_flush_buffers(queue, 0, start_index, flush_count); | 4367 | qeth_flush_buffers(queue, 0, start_index, flush_count); |
4368 | else if (!atomic_read(&queue->set_pci_flags_count)) | 4368 | else if (!atomic_read(&queue->set_pci_flags_count)) |
4369 | atomic_swap(&queue->state, QETH_OUT_Q_LOCKED_FLUSH); | 4369 | atomic_xchg(&queue->state, QETH_OUT_Q_LOCKED_FLUSH); |
4370 | /* | 4370 | /* |
4371 | * queue->state will go from LOCKED -> UNLOCKED or from | 4371 | * queue->state will go from LOCKED -> UNLOCKED or from |
4372 | * LOCKED_FLUSH -> LOCKED if output_handler wanted to 'notify' us | 4372 | * LOCKED_FLUSH -> LOCKED if output_handler wanted to 'notify' us |
diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c index c0871002d00d..d4a0fad3563b 100644 --- a/fs/partitions/mac.c +++ b/fs/partitions/mac.c | |||
@@ -74,6 +74,8 @@ int mac_partition(struct parsed_partitions *state, struct block_device *bdev) | |||
74 | be32_to_cpu(part->start_block) * (secsize/512), | 74 | be32_to_cpu(part->start_block) * (secsize/512), |
75 | be32_to_cpu(part->block_count) * (secsize/512)); | 75 | be32_to_cpu(part->block_count) * (secsize/512)); |
76 | 76 | ||
77 | if (!strnicmp(part->type, "Linux_RAID", 10)) | ||
78 | state->parts[slot].flags = 1; | ||
77 | #ifdef CONFIG_PPC_PMAC | 79 | #ifdef CONFIG_PPC_PMAC |
78 | /* | 80 | /* |
79 | * If this is the first bootable partition, tell the | 81 | * If this is the first bootable partition, tell the |
diff --git a/include/asm-m68knommu/dma-mapping.h b/include/asm-m68knommu/dma-mapping.h index 5622b855a577..6aeab18e58bd 100644 --- a/include/asm-m68knommu/dma-mapping.h +++ b/include/asm-m68knommu/dma-mapping.h | |||
@@ -1,9 +1,10 @@ | |||
1 | #ifndef _M68KNOMMU_DMA_MAPPING_H | 1 | #ifndef _M68KNOMMU_DMA_MAPPING_H |
2 | #define _M68KNOMMU_DMA_MAPPING_H | 2 | #define _M68KNOMMU_DMA_MAPPING_H |
3 | 3 | ||
4 | |||
5 | #ifdef CONFIG_PCI | 4 | #ifdef CONFIG_PCI |
6 | #include <asm-generic/dma-mapping.h> | 5 | #include <asm-generic/dma-mapping.h> |
6 | #else | ||
7 | #include <asm-generic/dma-mapping-broken.h> | ||
7 | #endif | 8 | #endif |
8 | 9 | ||
9 | #endif /* _M68KNOMMU_DMA_MAPPING_H */ | 10 | #endif /* _M68KNOMMU_DMA_MAPPING_H */ |
diff --git a/include/asm-m68knommu/m520xsim.h b/include/asm-m68knommu/m520xsim.h index 1dac22ea95ba..49d016e6391a 100644 --- a/include/asm-m68knommu/m520xsim.h +++ b/include/asm-m68knommu/m520xsim.h | |||
@@ -31,6 +31,16 @@ | |||
31 | #define MCFINT_QSPI 31 /* Interrupt number for QSPI */ | 31 | #define MCFINT_QSPI 31 /* Interrupt number for QSPI */ |
32 | #define MCFINT_PIT1 4 /* Interrupt number for PIT1 (PIT0 in processor) */ | 32 | #define MCFINT_PIT1 4 /* Interrupt number for PIT1 (PIT0 in processor) */ |
33 | 33 | ||
34 | /* | ||
35 | * SDRAM configuration registers. | ||
36 | */ | ||
37 | #define MCFSIM_SDMR 0x000a8000 /* SDRAM Mode/Extended Mode Register */ | ||
38 | #define MCFSIM_SDCR 0x000a8004 /* SDRAM Control Register */ | ||
39 | #define MCFSIM_SDCFG1 0x000a8008 /* SDRAM Configuration Register 1 */ | ||
40 | #define MCFSIM_SDCFG2 0x000a800c /* SDRAM Configuration Register 2 */ | ||
41 | #define MCFSIM_SDCS0 0x000a8110 /* SDRAM Chip Select 0 Configuration */ | ||
42 | #define MCFSIM_SDCS1 0x000a8114 /* SDRAM Chip Select 1 Configuration */ | ||
43 | |||
34 | 44 | ||
35 | #define MCF_GPIO_PAR_UART (0xA4036) | 45 | #define MCF_GPIO_PAR_UART (0xA4036) |
36 | #define MCF_GPIO_PAR_FECI2C (0xA4033) | 46 | #define MCF_GPIO_PAR_FECI2C (0xA4033) |
@@ -47,7 +57,7 @@ | |||
47 | 57 | ||
48 | #define ICR_INTRCONF 0x05 | 58 | #define ICR_INTRCONF 0x05 |
49 | #define MCFPIT_IMR MCFINTC_IMRL | 59 | #define MCFPIT_IMR MCFINTC_IMRL |
50 | #define MCFPIT_IMR_IBIT (1 << MCFINT_PIT1) | 60 | #define MCFPIT_IMR_IBIT (1 << MCFINT_PIT1) |
51 | 61 | ||
52 | /****************************************************************************/ | 62 | /****************************************************************************/ |
53 | #endif /* m520xsim_h */ | 63 | #endif /* m520xsim_h */ |
diff --git a/include/asm-m68knommu/scatterlist.h b/include/asm-m68knommu/scatterlist.h index 12309b181d29..2085d6ff8782 100644 --- a/include/asm-m68knommu/scatterlist.h +++ b/include/asm-m68knommu/scatterlist.h | |||
@@ -10,7 +10,7 @@ struct scatterlist { | |||
10 | unsigned int length; | 10 | unsigned int length; |
11 | }; | 11 | }; |
12 | 12 | ||
13 | #define sg_address(sg) (page_address((sg)->page) + (sg)->offset | 13 | #define sg_address(sg) (page_address((sg)->page) + (sg)->offset) |
14 | #define sg_dma_address(sg) ((sg)->dma_address) | 14 | #define sg_dma_address(sg) ((sg)->dma_address) |
15 | #define sg_dma_len(sg) ((sg)->length) | 15 | #define sg_dma_len(sg) ((sg)->length) |
16 | 16 | ||
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h index 81287d86329d..d92785030980 100644 --- a/include/asm-s390/cio.h +++ b/include/asm-s390/cio.h | |||
@@ -278,17 +278,16 @@ struct ccw_dev_id { | |||
278 | static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1, | 278 | static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1, |
279 | struct ccw_dev_id *dev_id2) | 279 | struct ccw_dev_id *dev_id2) |
280 | { | 280 | { |
281 | return !memcmp(dev_id1, dev_id2, sizeof(struct ccw_dev_id)); | 281 | if ((dev_id1->ssid == dev_id2->ssid) && |
282 | (dev_id1->devno == dev_id2->devno)) | ||
283 | return 1; | ||
284 | return 0; | ||
282 | } | 285 | } |
283 | 286 | ||
284 | extern int diag210(struct diag210 *addr); | 287 | extern int diag210(struct diag210 *addr); |
285 | 288 | ||
286 | extern void wait_cons_dev(void); | 289 | extern void wait_cons_dev(void); |
287 | 290 | ||
288 | extern void clear_all_subchannels(void); | ||
289 | |||
290 | extern void cio_reset_channel_paths(void); | ||
291 | |||
292 | extern void css_schedule_reprobe(void); | 291 | extern void css_schedule_reprobe(void); |
293 | 292 | ||
294 | extern void reipl_ccw_dev(struct ccw_dev_id *id); | 293 | extern void reipl_ccw_dev(struct ccw_dev_id *id); |
diff --git a/include/asm-s390/cpcmd.h b/include/asm-s390/cpcmd.h index 1fcf65be7a23..48a9eab16429 100644 --- a/include/asm-s390/cpcmd.h +++ b/include/asm-s390/cpcmd.h | |||
@@ -7,8 +7,8 @@ | |||
7 | * Christian Borntraeger (cborntra@de.ibm.com), | 7 | * Christian Borntraeger (cborntra@de.ibm.com), |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #ifndef __CPCMD__ | 10 | #ifndef _ASM_S390_CPCMD_H |
11 | #define __CPCMD__ | 11 | #define _ASM_S390_CPCMD_H |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * the lowlevel function for cpcmd | 14 | * the lowlevel function for cpcmd |
@@ -16,9 +16,6 @@ | |||
16 | */ | 16 | */ |
17 | extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code); | 17 | extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code); |
18 | 18 | ||
19 | #ifndef __s390x__ | ||
20 | #define cpcmd __cpcmd | ||
21 | #else | ||
22 | /* | 19 | /* |
23 | * cpcmd is the in-kernel interface for issuing CP commands | 20 | * cpcmd is the in-kernel interface for issuing CP commands |
24 | * | 21 | * |
@@ -33,6 +30,5 @@ extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code | |||
33 | * NOTE: If the response buffer is not below 2 GB, cpcmd can sleep | 30 | * NOTE: If the response buffer is not below 2 GB, cpcmd can sleep |
34 | */ | 31 | */ |
35 | extern int cpcmd(const char *cmd, char *response, int rlen, int *response_code); | 32 | extern int cpcmd(const char *cmd, char *response, int rlen, int *response_code); |
36 | #endif /*__s390x__*/ | ||
37 | 33 | ||
38 | #endif | 34 | #endif /* _ASM_S390_CPCMD_H */ |
diff --git a/include/asm-s390/kexec.h b/include/asm-s390/kexec.h index ce28ddda0f50..9c35c8ad1afd 100644 --- a/include/asm-s390/kexec.h +++ b/include/asm-s390/kexec.h | |||
@@ -26,7 +26,7 @@ | |||
26 | 26 | ||
27 | /* Maximum address we can use for the control pages */ | 27 | /* Maximum address we can use for the control pages */ |
28 | /* Not more than 2GB */ | 28 | /* Not more than 2GB */ |
29 | #define KEXEC_CONTROL_MEMORY_LIMIT (1<<31) | 29 | #define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31) |
30 | 30 | ||
31 | /* Allocate one page for the pdp and the second for the code */ | 31 | /* Allocate one page for the pdp and the second for the code */ |
32 | #define KEXEC_CONTROL_CODE_SIZE 4096 | 32 | #define KEXEC_CONTROL_CODE_SIZE 4096 |
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index 06583ed0bde7..74f7389bd3ee 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h | |||
@@ -362,6 +362,14 @@ static inline void set_prefix(__u32 address) | |||
362 | asm volatile("spx %0" : : "m" (address) : "memory"); | 362 | asm volatile("spx %0" : : "m" (address) : "memory"); |
363 | } | 363 | } |
364 | 364 | ||
365 | static inline __u32 store_prefix(void) | ||
366 | { | ||
367 | __u32 address; | ||
368 | |||
369 | asm volatile("stpx %0" : "=m" (address)); | ||
370 | return address; | ||
371 | } | ||
372 | |||
365 | #define __PANIC_MAGIC 0xDEADC0DE | 373 | #define __PANIC_MAGIC 0xDEADC0DE |
366 | 374 | ||
367 | #endif | 375 | #endif |
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 36bb6dacf008..2d968a69ed1f 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h | |||
@@ -110,13 +110,22 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
110 | #define VMALLOC_OFFSET (8*1024*1024) | 110 | #define VMALLOC_OFFSET (8*1024*1024) |
111 | #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \ | 111 | #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \ |
112 | & ~(VMALLOC_OFFSET-1)) | 112 | & ~(VMALLOC_OFFSET-1)) |
113 | |||
114 | /* | ||
115 | * We need some free virtual space to be able to do vmalloc. | ||
116 | * VMALLOC_MIN_SIZE defines the minimum size of the vmalloc | ||
117 | * area. On a machine with 2GB memory we make sure that we | ||
118 | * have at least 128MB free space for vmalloc. On a machine | ||
119 | * with 4TB we make sure we have at least 1GB. | ||
120 | */ | ||
113 | #ifndef __s390x__ | 121 | #ifndef __s390x__ |
114 | # define VMALLOC_END (0x7fffffffL) | 122 | #define VMALLOC_MIN_SIZE 0x8000000UL |
123 | #define VMALLOC_END 0x80000000UL | ||
115 | #else /* __s390x__ */ | 124 | #else /* __s390x__ */ |
116 | # define VMALLOC_END (0x40000000000L) | 125 | #define VMALLOC_MIN_SIZE 0x40000000UL |
126 | #define VMALLOC_END 0x40000000000UL | ||
117 | #endif /* __s390x__ */ | 127 | #endif /* __s390x__ */ |
118 | 128 | ||
119 | |||
120 | /* | 129 | /* |
121 | * A 31 bit pagetable entry of S390 has following format: | 130 | * A 31 bit pagetable entry of S390 has following format: |
122 | * | PFRA | | OS | | 131 | * | PFRA | | OS | |
diff --git a/include/asm-s390/reset.h b/include/asm-s390/reset.h new file mode 100644 index 000000000000..9b439cf67800 --- /dev/null +++ b/include/asm-s390/reset.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * include/asm-s390/reset.h | ||
3 | * | ||
4 | * Copyright IBM Corp. 2006 | ||
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #ifndef _ASM_S390_RESET_H | ||
9 | #define _ASM_S390_RESET_H | ||
10 | |||
11 | #include <linux/list.h> | ||
12 | |||
13 | struct reset_call { | ||
14 | struct list_head list; | ||
15 | void (*fn)(void); | ||
16 | }; | ||
17 | |||
18 | extern void register_reset_call(struct reset_call *reset); | ||
19 | extern void unregister_reset_call(struct reset_call *reset); | ||
20 | extern void s390_reset_system(void); | ||
21 | extern void (*s390_reset_mcck_handler)(void); | ||
22 | |||
23 | #endif /* _ASM_S390_RESET_H */ | ||
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h index 5d72eda8a11b..7664bacdd832 100644 --- a/include/asm-s390/setup.h +++ b/include/asm-s390/setup.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * include/asm-s390/setup.h | 2 | * include/asm-s390/setup.h |
3 | * | 3 | * |
4 | * S390 version | 4 | * S390 version |
5 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * Copyright IBM Corp. 1999,2006 |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #ifndef _ASM_S390_SETUP_H | 8 | #ifndef _ASM_S390_SETUP_H |
@@ -30,6 +30,17 @@ | |||
30 | #endif /* __s390x__ */ | 30 | #endif /* __s390x__ */ |
31 | #define COMMAND_LINE ((char *) (0x10480)) | 31 | #define COMMAND_LINE ((char *) (0x10480)) |
32 | 32 | ||
33 | #define CHUNK_READ_WRITE 0 | ||
34 | #define CHUNK_READ_ONLY 1 | ||
35 | |||
36 | struct mem_chunk { | ||
37 | unsigned long addr; | ||
38 | unsigned long size; | ||
39 | unsigned long type; | ||
40 | }; | ||
41 | |||
42 | extern struct mem_chunk memory_chunk[]; | ||
43 | |||
33 | /* | 44 | /* |
34 | * Machine features detected in head.S | 45 | * Machine features detected in head.S |
35 | */ | 46 | */ |
@@ -53,7 +64,6 @@ extern unsigned long machine_flags; | |||
53 | #define MACHINE_HAS_MVCOS (machine_flags & 512) | 64 | #define MACHINE_HAS_MVCOS (machine_flags & 512) |
54 | #endif /* __s390x__ */ | 65 | #endif /* __s390x__ */ |
55 | 66 | ||
56 | |||
57 | #define MACHINE_HAS_SCLP (!MACHINE_IS_P390) | 67 | #define MACHINE_HAS_SCLP (!MACHINE_IS_P390) |
58 | 68 | ||
59 | /* | 69 | /* |
@@ -71,7 +81,6 @@ extern unsigned int console_irq; | |||
71 | #define SET_CONSOLE_3215 do { console_mode = 2; } while (0) | 81 | #define SET_CONSOLE_3215 do { console_mode = 2; } while (0) |
72 | #define SET_CONSOLE_3270 do { console_mode = 3; } while (0) | 82 | #define SET_CONSOLE_3270 do { console_mode = 3; } while (0) |
73 | 83 | ||
74 | |||
75 | struct ipl_list_hdr { | 84 | struct ipl_list_hdr { |
76 | u32 len; | 85 | u32 len; |
77 | u8 reserved1[3]; | 86 | u8 reserved1[3]; |
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h index c3cf030ada4d..7097c96ed026 100644 --- a/include/asm-s390/smp.h +++ b/include/asm-s390/smp.h | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include <asm/lowcore.h> | 19 | #include <asm/lowcore.h> |
20 | #include <asm/sigp.h> | 20 | #include <asm/sigp.h> |
21 | #include <asm/ptrace.h> | ||
21 | 22 | ||
22 | /* | 23 | /* |
23 | s390 specific smp.c headers | 24 | s390 specific smp.c headers |
@@ -101,6 +102,13 @@ smp_call_function_on(void (*func) (void *info), void *info, | |||
101 | func(info); | 102 | func(info); |
102 | return 0; | 103 | return 0; |
103 | } | 104 | } |
105 | |||
106 | static inline void smp_send_stop(void) | ||
107 | { | ||
108 | /* Disable all interrupts/machine checks */ | ||
109 | __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK); | ||
110 | } | ||
111 | |||
104 | #define smp_cpu_not_running(cpu) 1 | 112 | #define smp_cpu_not_running(cpu) 1 |
105 | #define smp_get_cpu(cpu) ({ 0; }) | 113 | #define smp_get_cpu(cpu) ({ 0; }) |
106 | #define smp_put_cpu(cpu) ({ 0; }) | 114 | #define smp_put_cpu(cpu) ({ 0; }) |
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index ccbafe4bf2cb..bd0b05ae87d2 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h | |||
@@ -115,6 +115,16 @@ extern void account_system_vtime(struct task_struct *); | |||
115 | #define account_vtime(x) do { /* empty */ } while (0) | 115 | #define account_vtime(x) do { /* empty */ } while (0) |
116 | #endif | 116 | #endif |
117 | 117 | ||
118 | #ifdef CONFIG_PFAULT | ||
119 | extern void pfault_irq_init(void); | ||
120 | extern int pfault_init(void); | ||
121 | extern void pfault_fini(void); | ||
122 | #else /* CONFIG_PFAULT */ | ||
123 | #define pfault_irq_init() do { } while (0) | ||
124 | #define pfault_init() ({-1;}) | ||
125 | #define pfault_fini() do { } while (0) | ||
126 | #endif /* CONFIG_PFAULT */ | ||
127 | |||
118 | #define finish_arch_switch(prev) do { \ | 128 | #define finish_arch_switch(prev) do { \ |
119 | set_fs(current->thread.mm_segment); \ | 129 | set_fs(current->thread.mm_segment); \ |
120 | account_vtime(prev); \ | 130 | account_vtime(prev); \ |
diff --git a/include/asm-s390/termios.h b/include/asm-s390/termios.h index d1e29cca54c9..62b23caf370e 100644 --- a/include/asm-s390/termios.h +++ b/include/asm-s390/termios.h | |||
@@ -75,39 +75,7 @@ struct termio { | |||
75 | */ | 75 | */ |
76 | #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" | 76 | #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" |
77 | 77 | ||
78 | /* | 78 | #include <asm-generic/termios.h> |
79 | * Translate a "termio" structure into a "termios". Ugh. | ||
80 | */ | ||
81 | #define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ | ||
82 | unsigned short __tmp; \ | ||
83 | get_user(__tmp,&(termio)->x); \ | ||
84 | (termios)->x = (0xffff0000 & ((termios)->x)) | __tmp; \ | ||
85 | } | ||
86 | |||
87 | #define user_termio_to_kernel_termios(termios, termio) \ | ||
88 | ({ \ | ||
89 | SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \ | ||
90 | SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \ | ||
91 | SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \ | ||
92 | SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \ | ||
93 | copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ | ||
94 | }) | ||
95 | |||
96 | /* | ||
97 | * Translate a "termios" structure into a "termio". Ugh. | ||
98 | */ | ||
99 | #define kernel_termios_to_user_termio(termio, termios) \ | ||
100 | ({ \ | ||
101 | put_user((termios)->c_iflag, &(termio)->c_iflag); \ | ||
102 | put_user((termios)->c_oflag, &(termio)->c_oflag); \ | ||
103 | put_user((termios)->c_cflag, &(termio)->c_cflag); \ | ||
104 | put_user((termios)->c_lflag, &(termio)->c_lflag); \ | ||
105 | put_user((termios)->c_line, &(termio)->c_line); \ | ||
106 | copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ | ||
107 | }) | ||
108 | |||
109 | #define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) | ||
110 | #define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) | ||
111 | 79 | ||
112 | #endif /* __KERNEL__ */ | 80 | #endif /* __KERNEL__ */ |
113 | 81 | ||
diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h index 72ae4efddb49..73ac4e82217b 100644 --- a/include/asm-s390/uaccess.h +++ b/include/asm-s390/uaccess.h | |||
@@ -201,7 +201,7 @@ extern int __get_user_bad(void) __attribute__((noreturn)); | |||
201 | * Returns number of bytes that could not be copied. | 201 | * Returns number of bytes that could not be copied. |
202 | * On success, this will be zero. | 202 | * On success, this will be zero. |
203 | */ | 203 | */ |
204 | static inline unsigned long | 204 | static inline unsigned long __must_check |
205 | __copy_to_user(void __user *to, const void *from, unsigned long n) | 205 | __copy_to_user(void __user *to, const void *from, unsigned long n) |
206 | { | 206 | { |
207 | if (__builtin_constant_p(n) && (n <= 256)) | 207 | if (__builtin_constant_p(n) && (n <= 256)) |
@@ -226,7 +226,7 @@ __copy_to_user(void __user *to, const void *from, unsigned long n) | |||
226 | * Returns number of bytes that could not be copied. | 226 | * Returns number of bytes that could not be copied. |
227 | * On success, this will be zero. | 227 | * On success, this will be zero. |
228 | */ | 228 | */ |
229 | static inline unsigned long | 229 | static inline unsigned long __must_check |
230 | copy_to_user(void __user *to, const void *from, unsigned long n) | 230 | copy_to_user(void __user *to, const void *from, unsigned long n) |
231 | { | 231 | { |
232 | might_sleep(); | 232 | might_sleep(); |
@@ -252,7 +252,7 @@ copy_to_user(void __user *to, const void *from, unsigned long n) | |||
252 | * If some data could not be copied, this function will pad the copied | 252 | * If some data could not be copied, this function will pad the copied |
253 | * data to the requested size using zero bytes. | 253 | * data to the requested size using zero bytes. |
254 | */ | 254 | */ |
255 | static inline unsigned long | 255 | static inline unsigned long __must_check |
256 | __copy_from_user(void *to, const void __user *from, unsigned long n) | 256 | __copy_from_user(void *to, const void __user *from, unsigned long n) |
257 | { | 257 | { |
258 | if (__builtin_constant_p(n) && (n <= 256)) | 258 | if (__builtin_constant_p(n) && (n <= 256)) |
@@ -277,7 +277,7 @@ __copy_from_user(void *to, const void __user *from, unsigned long n) | |||
277 | * If some data could not be copied, this function will pad the copied | 277 | * If some data could not be copied, this function will pad the copied |
278 | * data to the requested size using zero bytes. | 278 | * data to the requested size using zero bytes. |
279 | */ | 279 | */ |
280 | static inline unsigned long | 280 | static inline unsigned long __must_check |
281 | copy_from_user(void *to, const void __user *from, unsigned long n) | 281 | copy_from_user(void *to, const void __user *from, unsigned long n) |
282 | { | 282 | { |
283 | might_sleep(); | 283 | might_sleep(); |
@@ -288,13 +288,13 @@ copy_from_user(void *to, const void __user *from, unsigned long n) | |||
288 | return n; | 288 | return n; |
289 | } | 289 | } |
290 | 290 | ||
291 | static inline unsigned long | 291 | static inline unsigned long __must_check |
292 | __copy_in_user(void __user *to, const void __user *from, unsigned long n) | 292 | __copy_in_user(void __user *to, const void __user *from, unsigned long n) |
293 | { | 293 | { |
294 | return uaccess.copy_in_user(n, to, from); | 294 | return uaccess.copy_in_user(n, to, from); |
295 | } | 295 | } |
296 | 296 | ||
297 | static inline unsigned long | 297 | static inline unsigned long __must_check |
298 | copy_in_user(void __user *to, const void __user *from, unsigned long n) | 298 | copy_in_user(void __user *to, const void __user *from, unsigned long n) |
299 | { | 299 | { |
300 | might_sleep(); | 300 | might_sleep(); |
@@ -306,7 +306,7 @@ copy_in_user(void __user *to, const void __user *from, unsigned long n) | |||
306 | /* | 306 | /* |
307 | * Copy a null terminated string from userspace. | 307 | * Copy a null terminated string from userspace. |
308 | */ | 308 | */ |
309 | static inline long | 309 | static inline long __must_check |
310 | strncpy_from_user(char *dst, const char __user *src, long count) | 310 | strncpy_from_user(char *dst, const char __user *src, long count) |
311 | { | 311 | { |
312 | long res = -EFAULT; | 312 | long res = -EFAULT; |
@@ -343,13 +343,13 @@ strnlen_user(const char __user * src, unsigned long n) | |||
343 | * Zero Userspace | 343 | * Zero Userspace |
344 | */ | 344 | */ |
345 | 345 | ||
346 | static inline unsigned long | 346 | static inline unsigned long __must_check |
347 | __clear_user(void __user *to, unsigned long n) | 347 | __clear_user(void __user *to, unsigned long n) |
348 | { | 348 | { |
349 | return uaccess.clear_user(n, to); | 349 | return uaccess.clear_user(n, to); |
350 | } | 350 | } |
351 | 351 | ||
352 | static inline unsigned long | 352 | static inline unsigned long __must_check |
353 | clear_user(void __user *to, unsigned long n) | 353 | clear_user(void __user *to, unsigned long n) |
354 | { | 354 | { |
355 | might_sleep(); | 355 | might_sleep(); |
diff --git a/include/asm-s390/zcrypt.h b/include/asm-s390/zcrypt.h index 7244c68464f2..b90e55888a55 100644 --- a/include/asm-s390/zcrypt.h +++ b/include/asm-s390/zcrypt.h | |||
@@ -180,40 +180,8 @@ struct ica_xcRB { | |||
180 | * for the implementation details for the contents of the | 180 | * for the implementation details for the contents of the |
181 | * block | 181 | * block |
182 | * | 182 | * |
183 | * Z90STAT_TOTALCOUNT | 183 | * ZSECSENDCPRB |
184 | * Return an integer count of all device types together. | 184 | * Send an arbitrary CPRB to a crypto card. |
185 | * | ||
186 | * Z90STAT_PCICACOUNT | ||
187 | * Return an integer count of all PCICAs. | ||
188 | * | ||
189 | * Z90STAT_PCICCCOUNT | ||
190 | * Return an integer count of all PCICCs. | ||
191 | * | ||
192 | * Z90STAT_PCIXCCMCL2COUNT | ||
193 | * Return an integer count of all MCL2 PCIXCCs. | ||
194 | * | ||
195 | * Z90STAT_PCIXCCMCL3COUNT | ||
196 | * Return an integer count of all MCL3 PCIXCCs. | ||
197 | * | ||
198 | * Z90STAT_CEX2CCOUNT | ||
199 | * Return an integer count of all CEX2Cs. | ||
200 | * | ||
201 | * Z90STAT_CEX2ACOUNT | ||
202 | * Return an integer count of all CEX2As. | ||
203 | * | ||
204 | * Z90STAT_REQUESTQ_COUNT | ||
205 | * Return an integer count of the number of entries waiting to be | ||
206 | * sent to a device. | ||
207 | * | ||
208 | * Z90STAT_PENDINGQ_COUNT | ||
209 | * Return an integer count of the number of entries sent to a | ||
210 | * device awaiting the reply. | ||
211 | * | ||
212 | * Z90STAT_TOTALOPEN_COUNT | ||
213 | * Return an integer count of the number of open file handles. | ||
214 | * | ||
215 | * Z90STAT_DOMAIN_INDEX | ||
216 | * Return the integer value of the Cryptographic Domain. | ||
217 | * | 185 | * |
218 | * Z90STAT_STATUS_MASK | 186 | * Z90STAT_STATUS_MASK |
219 | * Return an 64 element array of unsigned chars for the status of | 187 | * Return an 64 element array of unsigned chars for the status of |
@@ -235,28 +203,51 @@ struct ica_xcRB { | |||
235 | * of successfully completed requests per device since the device | 203 | * of successfully completed requests per device since the device |
236 | * was detected and made available. | 204 | * was detected and made available. |
237 | * | 205 | * |
238 | * ICAZ90STATUS (deprecated) | 206 | * Z90STAT_REQUESTQ_COUNT |
207 | * Return an integer count of the number of entries waiting to be | ||
208 | * sent to a device. | ||
209 | * | ||
210 | * Z90STAT_PENDINGQ_COUNT | ||
211 | * Return an integer count of the number of entries sent to all | ||
212 | * devices awaiting the reply. | ||
213 | * | ||
214 | * Z90STAT_TOTALOPEN_COUNT | ||
215 | * Return an integer count of the number of open file handles. | ||
216 | * | ||
217 | * Z90STAT_DOMAIN_INDEX | ||
218 | * Return the integer value of the Cryptographic Domain. | ||
219 | * | ||
220 | * The following ioctls are deprecated and should be no longer used: | ||
221 | * | ||
222 | * Z90STAT_TOTALCOUNT | ||
223 | * Return an integer count of all device types together. | ||
224 | * | ||
225 | * Z90STAT_PCICACOUNT | ||
226 | * Return an integer count of all PCICAs. | ||
227 | * | ||
228 | * Z90STAT_PCICCCOUNT | ||
229 | * Return an integer count of all PCICCs. | ||
230 | * | ||
231 | * Z90STAT_PCIXCCMCL2COUNT | ||
232 | * Return an integer count of all MCL2 PCIXCCs. | ||
233 | * | ||
234 | * Z90STAT_PCIXCCMCL3COUNT | ||
235 | * Return an integer count of all MCL3 PCIXCCs. | ||
236 | * | ||
237 | * Z90STAT_CEX2CCOUNT | ||
238 | * Return an integer count of all CEX2Cs. | ||
239 | * | ||
240 | * Z90STAT_CEX2ACOUNT | ||
241 | * Return an integer count of all CEX2As. | ||
242 | * | ||
243 | * ICAZ90STATUS | ||
239 | * Return some device driver status in a ica_z90_status struct | 244 | * Return some device driver status in a ica_z90_status struct |
240 | * This takes an ica_z90_status struct as its arg. | 245 | * This takes an ica_z90_status struct as its arg. |
241 | * | 246 | * |
242 | * NOTE: this ioctl() is deprecated, and has been replaced with | 247 | * Z90STAT_PCIXCCCOUNT |
243 | * single ioctl()s for each type of status being requested | ||
244 | * | ||
245 | * Z90STAT_PCIXCCCOUNT (deprecated) | ||
246 | * Return an integer count of all PCIXCCs (MCL2 + MCL3). | 248 | * Return an integer count of all PCIXCCs (MCL2 + MCL3). |
247 | * This is DEPRECATED now that MCL3 PCIXCCs are treated differently from | 249 | * This is DEPRECATED now that MCL3 PCIXCCs are treated differently from |
248 | * MCL2 PCIXCCs. | 250 | * MCL2 PCIXCCs. |
249 | * | ||
250 | * Z90QUIESCE (not recommended) | ||
251 | * Quiesce the driver. This is intended to stop all new | ||
252 | * requests from being processed. Its use is NOT recommended, | ||
253 | * except in circumstances where there is no other way to stop | ||
254 | * callers from accessing the driver. Its original use was to | ||
255 | * allow the driver to be "drained" of work in preparation for | ||
256 | * a system shutdown. | ||
257 | * | ||
258 | * NOTE: once issued, this ban on new work cannot be undone | ||
259 | * except by unloading and reloading the driver. | ||
260 | */ | 251 | */ |
261 | 252 | ||
262 | /** | 253 | /** |
diff --git a/include/linux/Kbuild b/include/linux/Kbuild index d7e04689304c..ff433126361f 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild | |||
@@ -60,8 +60,6 @@ header-y += fadvise.h | |||
60 | header-y += fd.h | 60 | header-y += fd.h |
61 | header-y += fdreg.h | 61 | header-y += fdreg.h |
62 | header-y += fib_rules.h | 62 | header-y += fib_rules.h |
63 | header-y += ftape-header-segment.h | ||
64 | header-y += ftape-vendors.h | ||
65 | header-y += fuse.h | 63 | header-y += fuse.h |
66 | header-y += futex.h | 64 | header-y += futex.h |
67 | header-y += genetlink.h | 65 | header-y += genetlink.h |
@@ -206,7 +204,6 @@ unifdef-y += fcntl.h | |||
206 | unifdef-y += filter.h | 204 | unifdef-y += filter.h |
207 | unifdef-y += flat.h | 205 | unifdef-y += flat.h |
208 | unifdef-y += fs.h | 206 | unifdef-y += fs.h |
209 | unifdef-y += ftape.h | ||
210 | unifdef-y += gameport.h | 207 | unifdef-y += gameport.h |
211 | unifdef-y += generic_serial.h | 208 | unifdef-y += generic_serial.h |
212 | unifdef-y += genhd.h | 209 | unifdef-y += genhd.h |
@@ -341,6 +338,5 @@ unifdef-y += wait.h | |||
341 | unifdef-y += wanrouter.h | 338 | unifdef-y += wanrouter.h |
342 | unifdef-y += watchdog.h | 339 | unifdef-y += watchdog.h |
343 | unifdef-y += xfrm.h | 340 | unifdef-y += xfrm.h |
344 | unifdef-y += zftape.h | ||
345 | 341 | ||
346 | objhdr-y += version.h | 342 | objhdr-y += version.h |
diff --git a/include/linux/ftape-header-segment.h b/include/linux/ftape-header-segment.h deleted file mode 100644 index 4732218f0708..000000000000 --- a/include/linux/ftape-header-segment.h +++ /dev/null | |||
@@ -1,122 +0,0 @@ | |||
1 | #ifndef _FTAPE_HEADER_SEGMENT_H | ||
2 | #define _FTAPE_HEADER_SEGMENT_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/include/linux/ftape-header-segment.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:28 $ | ||
25 | * | ||
26 | * This file defines some offsets into the header segment of a | ||
27 | * floppy tape cartridge. For use with the QIC-40/80/3010/3020 | ||
28 | * floppy-tape driver "ftape" for Linux. | ||
29 | */ | ||
30 | |||
31 | #define FT_SIGNATURE 0 /* must be 0xaa55aa55 */ | ||
32 | #define FT_FMT_CODE 4 | ||
33 | #define FT_REV_LEVEL 5 /* only for QIC-80 since. Rev. L (== 0x0c) */ | ||
34 | #define FT_HSEG_1 6 /* first header segment, except for format code 6 */ | ||
35 | #define FT_HSEG_2 8 /* second header segment, except for format code 6 */ | ||
36 | #define FT_FRST_SEG 10 /* first data segment, except for format code 6 */ | ||
37 | #define FT_LAST_SEG 12 /* last data segment, except for format code 6 */ | ||
38 | #define FT_FMT_DATE 14 /* date and time of most recent format, see below */ | ||
39 | #define FT_WR_DATE 18 /* date and time of most recent write or format */ | ||
40 | #define FT_SPT 24 /* segments per track */ | ||
41 | #define FT_TPC 26 /* tracks per cartridge */ | ||
42 | #define FT_FHM 27 /* floppy drive head (maximum of it) */ | ||
43 | #define FT_FTM 28 /* floppy track max. */ | ||
44 | #define FT_FSM 29 /* floppy sector max. (128) */ | ||
45 | #define FT_LABEL 30 /* floppy tape label */ | ||
46 | #define FT_LABEL_DATE 74 /* date and time the tape label was written */ | ||
47 | #define FT_LABEL_SZ (FT_LABEL_DATE - FT_LABEL) | ||
48 | #define FT_CMAP_START 78 /* starting segment of compression map */ | ||
49 | #define FT_FMT_ERROR 128 /* must be set to 0xff if remainder gets lost during | ||
50 | * tape format | ||
51 | */ | ||
52 | #define FT_SEG_CNT 130 /* number of seg. written, formatted or verified | ||
53 | * through lifetime of tape (why not read?) | ||
54 | */ | ||
55 | #define FT_INIT_DATE 138 /* date and time of initial tape format */ | ||
56 | #define FT_FMT_CNT 142 /* number of times tape has been formatted */ | ||
57 | #define FT_FSL_CNT 144 /* number of segments in failed sector log */ | ||
58 | #define FT_MK_CODE 146 /* id string of tape manufacturer */ | ||
59 | #define FT_LOT_CODE 190 /* tape manufacturer lot code */ | ||
60 | #define FT_6_HSEG_1 234 /* first header segment for format code 6 */ | ||
61 | #define FT_6_HSEG_2 238 /* second header segment for format code 6 */ | ||
62 | #define FT_6_FRST_SEG 242 /* first data segment for format code 6 */ | ||
63 | #define FT_6_LAST_SEG 246 /* last data segment for format code 6 */ | ||
64 | |||
65 | #define FT_FSL 256 | ||
66 | #define FT_HEADER_END 256 /* space beyond this point: | ||
67 | * format codes 2, 3 and 5: | ||
68 | * - failed sector log until byte 2047 | ||
69 | * - bad sector map in the reamining part of segment | ||
70 | * format codes 4 and 6: | ||
71 | * - bad sector map starts hear | ||
72 | */ | ||
73 | |||
74 | |||
75 | /* value to be stored at the FT_SIGNATURE offset | ||
76 | */ | ||
77 | #define FT_HSEG_MAGIC 0xaa55aa55 | ||
78 | #define FT_D2G_MAGIC 0x82288228 /* Ditto 2GB */ | ||
79 | |||
80 | /* data and time encoding: */ | ||
81 | #define FT_YEAR_SHIFT 25 | ||
82 | #define FT_YEAR_MASK 0xfe000000 | ||
83 | #define FT_YEAR_0 1970 | ||
84 | #define FT_YEAR_MAX 127 | ||
85 | #define FT_YEAR(year) ((((year)-FT_YEAR_0)<<FT_YEAR_SHIFT)&FT_YEAR_MASK) | ||
86 | |||
87 | #define FT_TIME_SHIFT 0 | ||
88 | #define FT_TIME_MASK 0x01FFFFFF | ||
89 | #define FT_TIME_MAX 0x01ea6dff /* last second of a year */ | ||
90 | #define FT_TIME(mo,d,h,m,s) \ | ||
91 | ((((s)+60*((m)+60*((h)+24*((d)+31*(mo))))) & FT_TIME_MASK)) | ||
92 | |||
93 | #define FT_TIME_STAMP(y,mo,d,h,m,s) (FT_YEAR(y) | FT_TIME(mo,d,h,m,s)) | ||
94 | |||
95 | /* values for the format code field */ | ||
96 | typedef enum { | ||
97 | fmt_normal = 2, /* QIC-80 post Rev. B 205Ft or 307Ft tape */ | ||
98 | fmt_1100ft = 3, /* QIC-80 post Rev. B 1100Ft tape */ | ||
99 | fmt_var = 4, /* QIC-80 post Rev. B variabel length format */ | ||
100 | fmt_425ft = 5, /* QIC-80 post Rev. B 425Ft tape */ | ||
101 | fmt_big = 6 /* QIC-3010/3020 variable length tape with more | ||
102 | * than 2^16 segments per tape | ||
103 | */ | ||
104 | } ft_format_type; | ||
105 | |||
106 | /* definitions for the failed sector log */ | ||
107 | #define FT_FSL_SIZE (2 * FT_SECTOR_SIZE - FT_HEADER_END) | ||
108 | #define FT_FSL_MAX_ENTRIES (FT_FSL_SIZE/sizeof(__u32)) | ||
109 | |||
110 | typedef struct ft_fsl_entry { | ||
111 | __u16 segment; | ||
112 | __u16 date; | ||
113 | } __attribute__ ((packed)) ft_fsl_entry; | ||
114 | |||
115 | |||
116 | /* date encoding for the failed sector log | ||
117 | * month: 1..12, day: 1..31, year: 1970..2097 | ||
118 | */ | ||
119 | #define FT_FSL_TIME_STAMP(y,m,d) \ | ||
120 | (((((y) - FT_YEAR_0)<<9)&0xfe00) | (((m)<<5)&0x01e0) | ((d)&0x001f)) | ||
121 | |||
122 | #endif /* _FTAPE_HEADER_SEGMENT_H */ | ||
diff --git a/include/linux/ftape-vendors.h b/include/linux/ftape-vendors.h deleted file mode 100644 index ec1a81f059e5..000000000000 --- a/include/linux/ftape-vendors.h +++ /dev/null | |||
@@ -1,137 +0,0 @@ | |||
1 | #ifndef _FTAPE_VENDORS_H | ||
2 | #define _FTAPE_VENDORS_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/include/linux/ftape-vendors.h,v $ | ||
24 | * $Revision: 1.6 $ | ||
25 | * $Date: 1997/10/09 15:38:11 $ | ||
26 | * | ||
27 | * This file contains the supported drive types with their | ||
28 | * QIC-117 spec. vendor code and drive dependent configuration | ||
29 | * information. | ||
30 | */ | ||
31 | |||
32 | typedef enum { | ||
33 | unknown_wake_up = 0, | ||
34 | no_wake_up, | ||
35 | wake_up_colorado, | ||
36 | wake_up_mountain, | ||
37 | wake_up_insight, | ||
38 | } wake_up_types; | ||
39 | |||
40 | typedef struct { | ||
41 | wake_up_types wake_up; /* see wake_up_types */ | ||
42 | char *name; /* Text describing the drive */ | ||
43 | } wakeup_method; | ||
44 | |||
45 | /* Note: order of entries in WAKEUP_METHODS must be so that a variable | ||
46 | * of type wake_up_types can be used as an index in the array. | ||
47 | */ | ||
48 | #define WAKEUP_METHODS { \ | ||
49 | { unknown_wake_up, "Unknown" }, \ | ||
50 | { no_wake_up, "None" }, \ | ||
51 | { wake_up_colorado, "Colorado" }, \ | ||
52 | { wake_up_mountain, "Mountain" }, \ | ||
53 | { wake_up_insight, "Motor-on" }, \ | ||
54 | } | ||
55 | |||
56 | typedef struct { | ||
57 | unsigned int vendor_id; /* vendor id from drive */ | ||
58 | int speed; /* maximum tape transport speed (ips) */ | ||
59 | wake_up_types wake_up; /* see wake_up_types */ | ||
60 | char *name; /* Text describing the drive */ | ||
61 | } vendor_struct; | ||
62 | |||
63 | #define UNKNOWN_VENDOR (-1) | ||
64 | |||
65 | #define QIC117_VENDORS { \ | ||
66 | /* see _vendor_struct */ \ | ||
67 | { 0x00000, 82, wake_up_colorado, "Colorado DJ-10 (old)" }, \ | ||
68 | { 0x00047, 90, wake_up_colorado, "Colorado DJ-10/DJ-20" }, \ | ||
69 | { 0x011c2, 84, wake_up_colorado, "Colorado 700" }, \ | ||
70 | { 0x011c3, 90, wake_up_colorado, "Colorado 1400" }, \ | ||
71 | { 0x011c4, 84, wake_up_colorado, "Colorado DJ-10/DJ-20 (new)" }, \ | ||
72 | { 0x011c5, 84, wake_up_colorado, "HP Colorado T1000" }, \ | ||
73 | { 0x011c6, 90, wake_up_colorado, "HP Colorado T3000" }, \ | ||
74 | { 0x00005, 45, wake_up_mountain, "Archive 5580i" }, \ | ||
75 | { 0x10005, 50, wake_up_insight, "Insight 80Mb, Irwin 80SX" }, \ | ||
76 | { 0x00140, 74, wake_up_mountain, "Archive S.Hornet [Identity/Escom]" }, \ | ||
77 | { 0x00146, 72, wake_up_mountain, "Archive 31250Q [Escom]" }, \ | ||
78 | { 0x0014a, 100, wake_up_mountain, "Archive XL9250i [Conner/Escom]" }, \ | ||
79 | { 0x0014c, 98, wake_up_mountain, "Conner C250MQT" }, \ | ||
80 | { 0x0014e, 80, wake_up_mountain, "Conner C250MQ" }, \ | ||
81 | { 0x00150, 80, wake_up_mountain, "Conner TSM420R/TST800R" }, \ | ||
82 | { 0x00152, 80, wake_up_mountain, "Conner TSM850R" }, \ | ||
83 | { 0x00156, 80, wake_up_mountain, "Conner TSM850R/1700R/TST3200R" }, \ | ||
84 | { 0x00180, 0, wake_up_mountain, "Summit SE 150" }, \ | ||
85 | { 0x00181, 85, wake_up_mountain, "Summit SE 250, Mountain FS8000" }, \ | ||
86 | { 0x001c1, 82, no_wake_up, "Wangtek 3040F" }, \ | ||
87 | { 0x001c8, 64, no_wake_up, "Wangtek 3080F" }, \ | ||
88 | { 0x001c8, 64, wake_up_colorado, "Wangtek 3080F" }, \ | ||
89 | { 0x001ca, 67, no_wake_up, "Wangtek 3080F (new)" }, \ | ||
90 | { 0x001cc, 77, wake_up_colorado, "Wangtek 3200 / Teac 700" }, \ | ||
91 | { 0x001cd, 75, wake_up_colorado, "Reveal TB1400" }, \ | ||
92 | { 0x00380, 85, wake_up_colorado, "Exabyte Eagle-96" }, \ | ||
93 | { 0x00381, 85, wake_up_colorado, "Exabyte Eagle TR-3" }, \ | ||
94 | { 0x00382, 85, wake_up_colorado, "Exabyte Eagle TR-3" }, \ | ||
95 | { 0x003ce, 77, wake_up_colorado, "Teac 800" }, \ | ||
96 | { 0x003cf, 0, wake_up_colorado, "Teac FT3010TR" }, \ | ||
97 | { 0x08880, 64, no_wake_up, "Iomega 250, Ditto 800" }, \ | ||
98 | { 0x08880, 64, wake_up_colorado, "Iomega 250, Ditto 800" }, \ | ||
99 | { 0x08880, 64, wake_up_insight, "Iomega 250, Ditto 800" }, \ | ||
100 | { 0x08881, 80, wake_up_colorado, "Iomega 700" }, \ | ||
101 | { 0x08882, 80, wake_up_colorado, "Iomega 3200" }, \ | ||
102 | { 0x08883, 80, wake_up_colorado, "Iomega DITTO 2GB" }, \ | ||
103 | { 0x00021, 70, no_wake_up, "AIWA CT-803" }, \ | ||
104 | { 0x004c0, 80, no_wake_up, "AIWA TD-S1600" }, \ | ||
105 | { 0x00021, 0, wake_up_mountain, "COREtape QIC80" }, \ | ||
106 | { 0x00441, 0, wake_up_mountain, "ComByte DoublePlay" }, \ | ||
107 | { 0x00481, 127, wake_up_mountain, "PERTEC MyTape 800" }, \ | ||
108 | { 0x00483, 130, wake_up_mountain, "PERTEC MyTape 3200" }, \ | ||
109 | { UNKNOWN_VENDOR, 0, no_wake_up, "unknown" } \ | ||
110 | } | ||
111 | |||
112 | #define QIC117_MAKE_CODES { \ | ||
113 | { 0, "Unassigned" }, \ | ||
114 | { 1, "Alloy Computer Products" }, \ | ||
115 | { 2, "3M" }, \ | ||
116 | { 3, "Tandberg Data" }, \ | ||
117 | { 4, "Colorado" }, \ | ||
118 | { 5, "Archive/Conner" }, \ | ||
119 | { 6, "Mountain/Summit Memory Systems" }, \ | ||
120 | { 7, "Wangtek/Rexon/Tecmar" }, \ | ||
121 | { 8, "Sony" }, \ | ||
122 | { 9, "Cipher Data Products" }, \ | ||
123 | { 10, "Irwin Magnetic Systems" }, \ | ||
124 | { 11, "Braemar" }, \ | ||
125 | { 12, "Verbatim" }, \ | ||
126 | { 13, "Core International" }, \ | ||
127 | { 14, "Exabyte" }, \ | ||
128 | { 15, "Teac" }, \ | ||
129 | { 16, "Gigatek" }, \ | ||
130 | { 17, "ComByte" }, \ | ||
131 | { 18, "PERTEC Memories" }, \ | ||
132 | { 19, "Aiwa" }, \ | ||
133 | { 71, "Colorado" }, \ | ||
134 | { 546, "Iomega Inc" }, \ | ||
135 | } | ||
136 | |||
137 | #endif /* _FTAPE_VENDORS_H */ | ||
diff --git a/include/linux/ftape.h b/include/linux/ftape.h deleted file mode 100644 index 7e7038cba86a..000000000000 --- a/include/linux/ftape.h +++ /dev/null | |||
@@ -1,201 +0,0 @@ | |||
1 | #ifndef _FTAPE_H | ||
2 | #define _FTAPE_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/include/linux/ftape.h,v $ | ||
24 | * $Revision: 1.17.6.4 $ | ||
25 | * $Date: 1997/11/25 01:52:54 $ | ||
26 | * | ||
27 | * This file contains global definitions, typedefs and macro's | ||
28 | * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. | ||
29 | */ | ||
30 | |||
31 | #define FTAPE_VERSION "ftape v3.04d 25/11/97" | ||
32 | |||
33 | #ifdef __KERNEL__ | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/mm.h> | ||
36 | #endif | ||
37 | #include <linux/types.h> | ||
38 | #include <linux/mtio.h> | ||
39 | |||
40 | #define FT_SECTOR(x) (x+1) /* sector offset into real sector */ | ||
41 | #define FT_SECTOR_SIZE 1024 | ||
42 | #define FT_SECTORS_PER_SEGMENT 32 | ||
43 | #define FT_ECC_SECTORS 3 | ||
44 | #define FT_SEGMENT_SIZE ((FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS) * FT_SECTOR_SIZE) | ||
45 | #define FT_BUFF_SIZE (FT_SECTORS_PER_SEGMENT * FT_SECTOR_SIZE) | ||
46 | |||
47 | /* | ||
48 | * bits of the minor device number that define drive selection | ||
49 | * methods. Could be used one day to access multiple tape | ||
50 | * drives on the same controller. | ||
51 | */ | ||
52 | #define FTAPE_SEL_A 0 | ||
53 | #define FTAPE_SEL_B 1 | ||
54 | #define FTAPE_SEL_C 2 | ||
55 | #define FTAPE_SEL_D 3 | ||
56 | #define FTAPE_SEL_MASK 3 | ||
57 | #define FTAPE_SEL(unit) ((unit) & FTAPE_SEL_MASK) | ||
58 | #define FTAPE_NO_REWIND 4 /* mask for minor nr */ | ||
59 | |||
60 | /* the following two may be reported when MTIOCGET is requested ... */ | ||
61 | typedef union { | ||
62 | struct { | ||
63 | __u8 error; | ||
64 | __u8 command; | ||
65 | } error; | ||
66 | long space; | ||
67 | } ft_drive_error; | ||
68 | typedef union { | ||
69 | struct { | ||
70 | __u8 drive_status; | ||
71 | __u8 drive_config; | ||
72 | __u8 tape_status; | ||
73 | } status; | ||
74 | long space; | ||
75 | } ft_drive_status; | ||
76 | |||
77 | #ifdef __KERNEL__ | ||
78 | |||
79 | #define FT_RQM_DELAY 12 | ||
80 | #define FT_MILLISECOND 1 | ||
81 | #define FT_SECOND 1000 | ||
82 | #define FT_FOREVER -1 | ||
83 | #ifndef HZ | ||
84 | #error "HZ undefined." | ||
85 | #endif | ||
86 | #define FT_USPT (1000000/HZ) /* microseconds per tick */ | ||
87 | |||
88 | /* This defines the number of retries that the driver will allow | ||
89 | * before giving up (and letting a higher level handle the error). | ||
90 | */ | ||
91 | #ifdef TESTING | ||
92 | #define FT_SOFT_RETRIES 1 /* number of low level retries */ | ||
93 | #define FT_RETRIES_ON_ECC_ERROR 3 /* ecc error when correcting segment */ | ||
94 | #else | ||
95 | #define FT_SOFT_RETRIES 6 /* number of low level retries (triple) */ | ||
96 | #define FT_RETRIES_ON_ECC_ERROR 3 /* ecc error when correcting segment */ | ||
97 | #endif | ||
98 | |||
99 | #ifndef THE_FTAPE_MAINTAINER | ||
100 | #define THE_FTAPE_MAINTAINER "the ftape maintainer" | ||
101 | #endif | ||
102 | |||
103 | /* Initialize missing configuration parameters. | ||
104 | */ | ||
105 | #ifndef CONFIG_FT_NR_BUFFERS | ||
106 | # define CONFIG_FT_NR_BUFFERS 3 | ||
107 | #endif | ||
108 | #ifndef CONFIG_FT_FDC_THR | ||
109 | # define CONFIG_FT_FDC_THR 8 | ||
110 | #endif | ||
111 | #ifndef CONFIG_FT_FDC_MAX_RATE | ||
112 | # define CONFIG_FT_FDC_MAX_RATE 2000 | ||
113 | #endif | ||
114 | #ifndef CONFIG_FT_FDC_BASE | ||
115 | # define CONFIG_FT_FDC_BASE 0 | ||
116 | #endif | ||
117 | #ifndef CONFIG_FT_FDC_IRQ | ||
118 | # define CONFIG_FT_FDC_IRQ 0 | ||
119 | #endif | ||
120 | #ifndef CONFIG_FT_FDC_DMA | ||
121 | # define CONFIG_FT_FDC_DMA 0 | ||
122 | #endif | ||
123 | |||
124 | /* Turn some booleans into numbers. | ||
125 | */ | ||
126 | #ifdef CONFIG_FT_PROBE_FC10 | ||
127 | # undef CONFIG_FT_PROBE_FC10 | ||
128 | # define CONFIG_FT_PROBE_FC10 1 | ||
129 | #else | ||
130 | # define CONFIG_FT_PROBE_FC10 0 | ||
131 | #endif | ||
132 | #ifdef CONFIG_FT_MACH2 | ||
133 | # undef CONFIG_FT_MACH2 | ||
134 | # define CONFIG_FT_MACH2 1 | ||
135 | #else | ||
136 | # define CONFIG_FT_MACH2 0 | ||
137 | #endif | ||
138 | |||
139 | /* Insert default settings | ||
140 | */ | ||
141 | #if CONFIG_FT_PROBE_FC10 == 1 | ||
142 | # if CONFIG_FT_FDC_BASE == 0 | ||
143 | # undef CONFIG_FT_FDC_BASE | ||
144 | # define CONFIG_FT_FDC_BASE 0x180 | ||
145 | # endif | ||
146 | # if CONFIG_FT_FDC_IRQ == 0 | ||
147 | # undef CONFIG_FT_FDC_IRQ | ||
148 | # define CONFIG_FT_FDC_IRQ 9 | ||
149 | # endif | ||
150 | # if CONFIG_FT_FDC_DMA == 0 | ||
151 | # undef CONFIG_FT_FDC_DMA | ||
152 | # define CONFIG_FT_FDC_DMA 3 | ||
153 | # endif | ||
154 | #elif CONFIG_FT_MACH2 == 1 /* CONFIG_FT_PROBE_FC10 == 1 */ | ||
155 | # if CONFIG_FT_FDC_BASE == 0 | ||
156 | # undef CONFIG_FT_FDC_BASE | ||
157 | # define CONFIG_FT_FDC_BASE 0x1E0 | ||
158 | # endif | ||
159 | # if CONFIG_FT_FDC_IRQ == 0 | ||
160 | # undef CONFIG_FT_FDC_IRQ | ||
161 | # define CONFIG_FT_FDC_IRQ 6 | ||
162 | # endif | ||
163 | # if CONFIG_FT_FDC_DMA == 0 | ||
164 | # undef CONFIG_FT_FDC_DMA | ||
165 | # define CONFIG_FT_FDC_DMA 2 | ||
166 | # endif | ||
167 | #elif defined(CONFIG_FT_ALT_FDC) /* CONFIG_FT_MACH2 */ | ||
168 | # if CONFIG_FT_FDC_BASE == 0 | ||
169 | # undef CONFIG_FT_FDC_BASE | ||
170 | # define CONFIG_FT_FDC_BASE 0x370 | ||
171 | # endif | ||
172 | # if CONFIG_FT_FDC_IRQ == 0 | ||
173 | # undef CONFIG_FT_FDC_IRQ | ||
174 | # define CONFIG_FT_FDC_IRQ 6 | ||
175 | # endif | ||
176 | # if CONFIG_FT_FDC_DMA == 0 | ||
177 | # undef CONFIG_FT_FDC_DMA | ||
178 | # define CONFIG_FT_FDC_DMA 2 | ||
179 | # endif | ||
180 | #else /* CONFIG_FT_ALT_FDC */ | ||
181 | # if CONFIG_FT_FDC_BASE == 0 | ||
182 | # undef CONFIG_FT_FDC_BASE | ||
183 | # define CONFIG_FT_FDC_BASE 0x3f0 | ||
184 | # endif | ||
185 | # if CONFIG_FT_FDC_IRQ == 0 | ||
186 | # undef CONFIG_FT_FDC_IRQ | ||
187 | # define CONFIG_FT_FDC_IRQ 6 | ||
188 | # endif | ||
189 | # if CONFIG_FT_FDC_DMA == 0 | ||
190 | # undef CONFIG_FT_FDC_DMA | ||
191 | # define CONFIG_FT_FDC_DMA 2 | ||
192 | # endif | ||
193 | #endif /* standard FDC */ | ||
194 | |||
195 | /* some useful macro's | ||
196 | */ | ||
197 | #define NR_ITEMS(x) (int)(sizeof(x)/ sizeof(*x)) | ||
198 | |||
199 | #endif /* __KERNEL__ */ | ||
200 | |||
201 | #endif | ||
diff --git a/include/linux/zftape.h b/include/linux/zftape.h deleted file mode 100644 index b057c65366c6..000000000000 --- a/include/linux/zftape.h +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_H | ||
2 | #define _ZFTAPE_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/include/linux/zftape.h,v $ | ||
23 | * $Revision: 1.12 $ | ||
24 | * $Date: 1997/10/21 11:02:37 $ | ||
25 | * | ||
26 | * Special ioctl and other global info for the zftape VFS | ||
27 | * interface for the QIC-40/80/3010/3020 floppy-tape driver for | ||
28 | * Linux. | ||
29 | */ | ||
30 | |||
31 | #define ZFTAPE_VERSION "zftape for " FTAPE_VERSION | ||
32 | |||
33 | #include <linux/ftape.h> | ||
34 | |||
35 | #define ZFTAPE_LABEL "Ftape - The Linux Floppy Tape Project!" | ||
36 | |||
37 | /* Bits of the minor device number that control the operation mode */ | ||
38 | #define ZFT_Q80_MODE (1 << 3) | ||
39 | #define ZFT_ZIP_MODE (1 << 4) | ||
40 | #define ZFT_RAW_MODE (1 << 5) | ||
41 | #define ZFT_MINOR_OP_MASK (ZFT_Q80_MODE | \ | ||
42 | ZFT_ZIP_MODE | \ | ||
43 | ZFT_RAW_MODE) | ||
44 | #define ZFT_MINOR_MASK (FTAPE_SEL_MASK | \ | ||
45 | ZFT_MINOR_OP_MASK | \ | ||
46 | FTAPE_NO_REWIND) | ||
47 | |||
48 | #ifdef ZFT_OBSOLETE | ||
49 | struct mtblksz { | ||
50 | unsigned int mt_blksz; | ||
51 | }; | ||
52 | #define MTIOC_ZFTAPE_GETBLKSZ _IOR('m', 104, struct mtblksz) | ||
53 | #endif | ||
54 | |||
55 | #ifdef __KERNEL__ | ||
56 | |||
57 | extern int zft_init(void); | ||
58 | |||
59 | static inline __s64 zft_div_blksz(__s64 value, __u32 blk_sz) | ||
60 | { | ||
61 | if (blk_sz == 1) { | ||
62 | return value; | ||
63 | } else { | ||
64 | return (__s64)(((__u32)(value >> 10) + (blk_sz >> 10) - 1) | ||
65 | / (blk_sz >> 10)); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | static inline __s64 zft_mul_blksz(__s64 value, __u32 blk_sz) | ||
70 | { | ||
71 | if (blk_sz == 1) { | ||
72 | return value; | ||
73 | } else { | ||
74 | /* if blk_sz != 1, then it is a multiple of 1024. In | ||
75 | * this case, `value' will also fit into 32 bits. | ||
76 | * | ||
77 | * Actually, this limits the capacity to 42 | ||
78 | * bits. This is (2^32)*1024, roughly a thousand | ||
79 | * times 2GB, or 3 Terabytes. Hopefully this is enough | ||
80 | */ | ||
81 | return(__s64)(((__u32)(value)*(blk_sz>>10))<<10); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | #endif | ||
86 | |||
87 | #endif | ||
diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig index dac89166eb18..80f469887691 100644 --- a/net/dccp/ccids/Kconfig +++ b/net/dccp/ccids/Kconfig | |||
@@ -89,4 +89,37 @@ config IP_DCCP_CCID3_DEBUG | |||
89 | parameter to 0 or 1. | 89 | parameter to 0 or 1. |
90 | 90 | ||
91 | If in doubt, say N. | 91 | If in doubt, say N. |
92 | |||
93 | config IP_DCCP_CCID3_RTO | ||
94 | int "Use higher bound for nofeedback timer" | ||
95 | default 100 | ||
96 | depends on IP_DCCP_CCID3 && EXPERIMENTAL | ||
97 | ---help--- | ||
98 | Use higher lower bound for nofeedback timer expiration. | ||
99 | |||
100 | The TFRC nofeedback timer normally expires after the maximum of 4 | ||
101 | RTTs and twice the current send interval (RFC 3448, 4.3). On LANs | ||
102 | with a small RTT this can mean a high processing load and reduced | ||
103 | performance, since then the nofeedback timer is triggered very | ||
104 | frequently. | ||
105 | |||
106 | This option enables to set a higher lower bound for the nofeedback | ||
107 | value. Values in units of milliseconds can be set here. | ||
108 | |||
109 | A value of 0 disables this feature by enforcing the value specified | ||
110 | in RFC 3448. The following values have been suggested as bounds for | ||
111 | experimental use: | ||
112 | * 16-20ms to match the typical multimedia inter-frame interval | ||
113 | * 100ms as a reasonable compromise [default] | ||
114 | * 1000ms corresponds to the lower TCP RTO bound (RFC 2988, 2.4) | ||
115 | |||
116 | The default of 100ms is a compromise between a large value for | ||
117 | efficient DCCP implementations, and a small value to avoid disrupting | ||
118 | the network in times of congestion. | ||
119 | |||
120 | The purpose of the nofeedback timer is to slow DCCP down when there | ||
121 | is serious network congestion: experimenting with larger values should | ||
122 | therefore not be performed on WANs. | ||
123 | |||
124 | |||
92 | endmenu | 125 | endmenu |
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 70ebe705eb75..cf8c07b2704f 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -121,12 +121,15 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx) | |||
121 | /* | 121 | /* |
122 | * Update X by | 122 | * Update X by |
123 | * If (p > 0) | 123 | * If (p > 0) |
124 | * x_calc = calcX(s, R, p); | 124 | * X_calc = calcX(s, R, p); |
125 | * X = max(min(X_calc, 2 * X_recv), s / t_mbi); | 125 | * X = max(min(X_calc, 2 * X_recv), s / t_mbi); |
126 | * Else | 126 | * Else |
127 | * If (now - tld >= R) | 127 | * If (now - tld >= R) |
128 | * X = max(min(2 * X, 2 * X_recv), s / R); | 128 | * X = max(min(2 * X, 2 * X_recv), s / R); |
129 | * tld = now; | 129 | * tld = now; |
130 | * | ||
131 | * If X has changed, we also update the scheduled send time t_now, | ||
132 | * the inter-packet interval t_ipi, and the delta value. | ||
130 | */ | 133 | */ |
131 | static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) | 134 | static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) |
132 | 135 | ||
@@ -134,8 +137,7 @@ static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) | |||
134 | struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); | 137 | struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); |
135 | const __u32 old_x = hctx->ccid3hctx_x; | 138 | const __u32 old_x = hctx->ccid3hctx_x; |
136 | 139 | ||
137 | /* To avoid large error in calcX */ | 140 | if (hctx->ccid3hctx_p > 0) { |
138 | if (hctx->ccid3hctx_p >= TFRC_SMALLEST_P) { | ||
139 | hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s, | 141 | hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s, |
140 | hctx->ccid3hctx_rtt, | 142 | hctx->ccid3hctx_rtt, |
141 | hctx->ccid3hctx_p); | 143 | hctx->ccid3hctx_p); |
@@ -223,16 +225,14 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) | |||
223 | ccid3_tx_state_name(hctx->ccid3hctx_state)); | 225 | ccid3_tx_state_name(hctx->ccid3hctx_state)); |
224 | /* Halve sending rate */ | 226 | /* Halve sending rate */ |
225 | 227 | ||
226 | /* If (X_calc > 2 * X_recv) | 228 | /* If (p == 0 || X_calc > 2 * X_recv) |
227 | * X_recv = max(X_recv / 2, s / (2 * t_mbi)); | 229 | * X_recv = max(X_recv / 2, s / (2 * t_mbi)); |
228 | * Else | 230 | * Else |
229 | * X_recv = X_calc / 4; | 231 | * X_recv = X_calc / 4; |
230 | */ | 232 | */ |
231 | BUG_ON(hctx->ccid3hctx_p >= TFRC_SMALLEST_P && | 233 | BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc); |
232 | hctx->ccid3hctx_x_calc == 0); | ||
233 | 234 | ||
234 | /* check also if p is zero -> x_calc is infinity? */ | 235 | if (hctx->ccid3hctx_p == 0 || |
235 | if (hctx->ccid3hctx_p < TFRC_SMALLEST_P || | ||
236 | hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv) | 236 | hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv) |
237 | hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2, | 237 | hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2, |
238 | hctx->ccid3hctx_s / (2 * TFRC_T_MBI)); | 238 | hctx->ccid3hctx_s / (2 * TFRC_T_MBI)); |
@@ -245,9 +245,10 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) | |||
245 | } | 245 | } |
246 | /* | 246 | /* |
247 | * Schedule no feedback timer to expire in | 247 | * Schedule no feedback timer to expire in |
248 | * max(4 * R, 2 * s/X) = max(4 * R, 2 * t_ipi) | 248 | * max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi) |
249 | * See comments in packet_recv() regarding the value of t_RTO. | ||
249 | */ | 250 | */ |
250 | t_nfb = max(4 * hctx->ccid3hctx_rtt, 2 * hctx->ccid3hctx_t_ipi); | 251 | t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi); |
251 | break; | 252 | break; |
252 | case TFRC_SSTATE_NO_SENT: | 253 | case TFRC_SSTATE_NO_SENT: |
253 | DCCP_BUG("Illegal %s state NO_SENT, sk=%p", dccp_role(sk), sk); | 254 | DCCP_BUG("Illegal %s state NO_SENT, sk=%p", dccp_role(sk), sk); |
@@ -338,7 +339,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) | |||
338 | * else | 339 | * else |
339 | * // send the packet in (t_nom - t_now) milliseconds. | 340 | * // send the packet in (t_nom - t_now) milliseconds. |
340 | */ | 341 | */ |
341 | if (delay >= hctx->ccid3hctx_delta) | 342 | if (delay - (long)hctx->ccid3hctx_delta >= 0) |
342 | return delay / 1000L; | 343 | return delay / 1000L; |
343 | break; | 344 | break; |
344 | case TFRC_SSTATE_TERM: | 345 | case TFRC_SSTATE_TERM: |
@@ -412,10 +413,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
412 | struct dccp_tx_hist_entry *packet; | 413 | struct dccp_tx_hist_entry *packet; |
413 | struct timeval now; | 414 | struct timeval now; |
414 | unsigned long t_nfb; | 415 | unsigned long t_nfb; |
415 | u32 t_elapsed; | ||
416 | u32 pinv; | 416 | u32 pinv; |
417 | u32 x_recv; | 417 | long r_sample, t_elapsed; |
418 | u32 r_sample; | ||
419 | 418 | ||
420 | BUG_ON(hctx == NULL); | 419 | BUG_ON(hctx == NULL); |
421 | 420 | ||
@@ -426,31 +425,44 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
426 | 425 | ||
427 | opt_recv = &hctx->ccid3hctx_options_received; | 426 | opt_recv = &hctx->ccid3hctx_options_received; |
428 | 427 | ||
429 | t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10; | ||
430 | x_recv = opt_recv->ccid3or_receive_rate; | ||
431 | pinv = opt_recv->ccid3or_loss_event_rate; | ||
432 | |||
433 | switch (hctx->ccid3hctx_state) { | 428 | switch (hctx->ccid3hctx_state) { |
434 | case TFRC_SSTATE_NO_FBACK: | 429 | case TFRC_SSTATE_NO_FBACK: |
435 | case TFRC_SSTATE_FBACK: | 430 | case TFRC_SSTATE_FBACK: |
436 | /* Calculate new round trip sample by | 431 | /* get packet from history to look up t_recvdata */ |
437 | * R_sample = (now - t_recvdata) - t_delay */ | ||
438 | /* get t_recvdata from history */ | ||
439 | packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist, | 432 | packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist, |
440 | DCCP_SKB_CB(skb)->dccpd_ack_seq); | 433 | DCCP_SKB_CB(skb)->dccpd_ack_seq); |
441 | if (unlikely(packet == NULL)) { | 434 | if (unlikely(packet == NULL)) { |
442 | DCCP_WARN("%s, sk=%p, seqno %llu(%s) does't exist " | 435 | DCCP_WARN("%s(%p), seqno %llu(%s) doesn't exist " |
443 | "in history!\n", dccp_role(sk), sk, | 436 | "in history!\n", dccp_role(sk), sk, |
444 | (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq, | 437 | (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq, |
445 | dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type)); | 438 | dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type)); |
446 | return; | 439 | return; |
447 | } | 440 | } |
448 | 441 | ||
449 | /* Update RTT */ | 442 | /* Update receive rate */ |
443 | hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate; | ||
444 | |||
445 | /* Update loss event rate */ | ||
446 | pinv = opt_recv->ccid3or_loss_event_rate; | ||
447 | if (pinv == ~0U || pinv == 0) | ||
448 | hctx->ccid3hctx_p = 0; | ||
449 | else | ||
450 | hctx->ccid3hctx_p = 1000000 / pinv; | ||
451 | |||
450 | dccp_timestamp(sk, &now); | 452 | dccp_timestamp(sk, &now); |
451 | r_sample = timeval_delta(&now, &packet->dccphtx_tstamp); | 453 | |
452 | if (unlikely(r_sample <= t_elapsed)) | 454 | /* |
453 | DCCP_WARN("r_sample=%uus,t_elapsed=%uus\n", | 455 | * Calculate new round trip sample as per [RFC 3448, 4.3] by |
456 | * R_sample = (now - t_recvdata) - t_elapsed | ||
457 | */ | ||
458 | r_sample = timeval_delta(&now, &packet->dccphtx_tstamp); | ||
459 | t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10; | ||
460 | |||
461 | if (unlikely(r_sample <= 0)) { | ||
462 | DCCP_WARN("WARNING: R_sample (%ld) <= 0!\n", r_sample); | ||
463 | r_sample = 0; | ||
464 | } else if (unlikely(r_sample <= t_elapsed)) | ||
465 | DCCP_WARN("WARNING: r_sample=%ldus <= t_elapsed=%ldus\n", | ||
454 | r_sample, t_elapsed); | 466 | r_sample, t_elapsed); |
455 | else | 467 | else |
456 | r_sample -= t_elapsed; | 468 | r_sample -= t_elapsed; |
@@ -473,31 +485,25 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
473 | hctx->ccid3hctx_t_ld = now; | 485 | hctx->ccid3hctx_t_ld = now; |
474 | 486 | ||
475 | ccid3_update_send_time(hctx); | 487 | ccid3_update_send_time(hctx); |
476 | ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK); | ||
477 | } else { | ||
478 | hctx->ccid3hctx_rtt = (hctx->ccid3hctx_rtt * 9) / 10 + | ||
479 | r_sample / 10; | ||
480 | ccid3_hc_tx_update_x(sk, &now); | ||
481 | } | ||
482 | 488 | ||
483 | ccid3_pr_debug("%s, sk=%p, New RTT estimate=%uus, " | 489 | ccid3_pr_debug("%s(%p), s=%u, w_init=%u, " |
484 | "r_sample=%us\n", dccp_role(sk), sk, | 490 | "R_sample=%ldus, X=%u\n", dccp_role(sk), |
485 | hctx->ccid3hctx_rtt, r_sample); | 491 | sk, hctx->ccid3hctx_s, w_init, r_sample, |
492 | hctx->ccid3hctx_x); | ||
486 | 493 | ||
487 | /* Update receive rate */ | 494 | ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK); |
488 | hctx->ccid3hctx_x_recv = x_recv;/* X_recv in bytes per sec */ | 495 | } else { |
496 | hctx->ccid3hctx_rtt = (9 * hctx->ccid3hctx_rtt + | ||
497 | (u32)r_sample ) / 10; | ||
489 | 498 | ||
490 | /* Update loss event rate */ | 499 | ccid3_hc_tx_update_x(sk, &now); |
491 | if (pinv == ~0 || pinv == 0) | ||
492 | hctx->ccid3hctx_p = 0; | ||
493 | else { | ||
494 | hctx->ccid3hctx_p = 1000000 / pinv; | ||
495 | 500 | ||
496 | if (hctx->ccid3hctx_p < TFRC_SMALLEST_P) { | 501 | ccid3_pr_debug("%s(%p), RTT=%uus (sample=%ldus), s=%u, " |
497 | hctx->ccid3hctx_p = TFRC_SMALLEST_P; | 502 | "p=%u, X_calc=%u, X=%u\n", dccp_role(sk), |
498 | ccid3_pr_debug("%s, sk=%p, Smallest p used!\n", | 503 | sk, hctx->ccid3hctx_rtt, r_sample, |
499 | dccp_role(sk), sk); | 504 | hctx->ccid3hctx_s, hctx->ccid3hctx_p, |
500 | } | 505 | hctx->ccid3hctx_x_calc, |
506 | hctx->ccid3hctx_x); | ||
501 | } | 507 | } |
502 | 508 | ||
503 | /* unschedule no feedback timer */ | 509 | /* unschedule no feedback timer */ |
@@ -512,16 +518,20 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
512 | */ | 518 | */ |
513 | sk->sk_write_space(sk); | 519 | sk->sk_write_space(sk); |
514 | 520 | ||
515 | /* Update timeout interval. We use the alternative variant of | 521 | /* |
516 | * [RFC 3448, 3.1] which sets the upper bound of t_rto to one | 522 | * Update timeout interval for the nofeedback timer. |
517 | * second, as it is suggested for TCP (see RFC 2988, 2.4). */ | 523 | * We use a configuration option to increase the lower bound. |
524 | * This can help avoid triggering the nofeedback timer too often | ||
525 | * ('spinning') on LANs with small RTTs. | ||
526 | */ | ||
518 | hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt, | 527 | hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt, |
519 | USEC_PER_SEC ); | 528 | CONFIG_IP_DCCP_CCID3_RTO * |
529 | (USEC_PER_SEC/1000) ); | ||
520 | /* | 530 | /* |
521 | * Schedule no feedback timer to expire in | 531 | * Schedule no feedback timer to expire in |
522 | * max(4 * R, 2 * s/X) = max(4 * R, 2 * t_ipi) | 532 | * max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi) |
523 | */ | 533 | */ |
524 | t_nfb = max(4 * hctx->ccid3hctx_rtt, 2 * hctx->ccid3hctx_t_ipi); | 534 | t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi); |
525 | 535 | ||
526 | ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to " | 536 | ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to " |
527 | "expire in %lu jiffies (%luus)\n", | 537 | "expire in %lu jiffies (%luus)\n", |
@@ -535,7 +545,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
535 | hctx->ccid3hctx_idle = 1; | 545 | hctx->ccid3hctx_idle = 1; |
536 | break; | 546 | break; |
537 | case TFRC_SSTATE_NO_SENT: | 547 | case TFRC_SSTATE_NO_SENT: |
538 | DCCP_WARN("Illegal ACK received - no packet has been sent\n"); | 548 | if (dccp_sk(sk)->dccps_role == DCCP_ROLE_CLIENT) |
549 | DCCP_WARN("Illegal ACK received - no packet sent\n"); | ||
539 | /* fall through */ | 550 | /* fall through */ |
540 | case TFRC_SSTATE_TERM: /* ignore feedback when closing */ | 551 | case TFRC_SSTATE_TERM: /* ignore feedback when closing */ |
541 | break; | 552 | break; |
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 27cb20ae1da8..07596d704ef9 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h | |||
@@ -51,8 +51,6 @@ | |||
51 | /* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */ | 51 | /* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */ |
52 | #define TFRC_T_MBI 64 | 52 | #define TFRC_T_MBI 64 |
53 | 53 | ||
54 | #define TFRC_SMALLEST_P 40 | ||
55 | |||
56 | enum ccid3_options { | 54 | enum ccid3_options { |
57 | TFRC_OPT_LOSS_EVENT_RATE = 192, | 55 | TFRC_OPT_LOSS_EVENT_RATE = 192, |
58 | TFRC_OPT_LOSS_INTERVALS = 193, | 56 | TFRC_OPT_LOSS_INTERVALS = 193, |
diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c index 2601012383fb..ddac2c511e2f 100644 --- a/net/dccp/ccids/lib/tfrc_equation.c +++ b/net/dccp/ccids/lib/tfrc_equation.c | |||
@@ -18,10 +18,79 @@ | |||
18 | #include "tfrc.h" | 18 | #include "tfrc.h" |
19 | 19 | ||
20 | #define TFRC_CALC_X_ARRSIZE 500 | 20 | #define TFRC_CALC_X_ARRSIZE 500 |
21 | #define TFRC_CALC_X_SPLIT 50000 /* 0.05 * 1000000, details below */ | ||
22 | #define TFRC_SMALLEST_P (TFRC_CALC_X_SPLIT/TFRC_CALC_X_ARRSIZE) | ||
21 | 23 | ||
22 | #define TFRC_CALC_X_SPLIT 50000 | 24 | /* |
23 | /* equivalent to 0.05 */ | 25 | TFRC TCP Reno Throughput Equation Lookup Table for f(p) |
24 | 26 | ||
27 | The following two-column lookup table implements a part of the TCP throughput | ||
28 | equation from [RFC 3448, sec. 3.1]: | ||
29 | |||
30 | s | ||
31 | X_calc = -------------------------------------------------------------- | ||
32 | R * sqrt(2*b*p/3) + (3 * t_RTO * sqrt(3*b*p/8) * (p + 32*p^3)) | ||
33 | |||
34 | Where: | ||
35 | X is the transmit rate in bytes/second | ||
36 | s is the packet size in bytes | ||
37 | R is the round trip time in seconds | ||
38 | p is the loss event rate, between 0 and 1.0, of the number of loss | ||
39 | events as a fraction of the number of packets transmitted | ||
40 | t_RTO is the TCP retransmission timeout value in seconds | ||
41 | b is the number of packets acknowledged by a single TCP ACK | ||
42 | |||
43 | We can assume that b = 1 and t_RTO is 4 * R. The equation now becomes: | ||
44 | |||
45 | s | ||
46 | X_calc = ------------------------------------------------------- | ||
47 | R * sqrt(p*2/3) + (12 * R * sqrt(p*3/8) * (p + 32*p^3)) | ||
48 | |||
49 | which we can break down into: | ||
50 | |||
51 | s | ||
52 | X_calc = --------- | ||
53 | R * f(p) | ||
54 | |||
55 | where f(p) is given for 0 < p <= 1 by: | ||
56 | |||
57 | f(p) = sqrt(2*p/3) + 12 * sqrt(3*p/8) * (p + 32*p^3) | ||
58 | |||
59 | Since this is kernel code, floating-point arithmetic is avoided in favour of | ||
60 | integer arithmetic. This means that nearly all fractional parameters are | ||
61 | scaled by 1000000: | ||
62 | * the parameters p and R | ||
63 | * the return result f(p) | ||
64 | The lookup table therefore actually tabulates the following function g(q): | ||
65 | |||
66 | g(q) = 1000000 * f(q/1000000) | ||
67 | |||
68 | Hence, when p <= 1, q must be less than or equal to 1000000. To achieve finer | ||
69 | granularity for the practically more relevant case of small values of p (up to | ||
70 | 5%), the second column is used; the first one ranges up to 100%. This split | ||
71 | corresponds to the value of q = TFRC_CALC_X_SPLIT. At the same time this also | ||
72 | determines the smallest resolution possible with this lookup table: | ||
73 | |||
74 | TFRC_SMALLEST_P = TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE | ||
75 | |||
76 | The entire table is generated by: | ||
77 | for(i=0; i < TFRC_CALC_X_ARRSIZE; i++) { | ||
78 | lookup[i][0] = g((i+1) * 1000000/TFRC_CALC_X_ARRSIZE); | ||
79 | lookup[i][1] = g((i+1) * TFRC_CALC_X_SPLIT/TFRC_CALC_X_ARRSIZE); | ||
80 | } | ||
81 | |||
82 | With the given configuration, we have, with M = TFRC_CALC_X_ARRSIZE-1, | ||
83 | lookup[0][0] = g(1000000/(M+1)) = 1000000 * f(0.2%) | ||
84 | lookup[M][0] = g(1000000) = 1000000 * f(100%) | ||
85 | lookup[0][1] = g(TFRC_SMALLEST_P) = 1000000 * f(0.01%) | ||
86 | lookup[M][1] = g(TFRC_CALC_X_SPLIT) = 1000000 * f(5%) | ||
87 | |||
88 | In summary, the two columns represent f(p) for the following ranges: | ||
89 | * The first column is for 0.002 <= p <= 1.0 | ||
90 | * The second column is for 0.0001 <= p <= 0.05 | ||
91 | Where the columns overlap, the second (finer-grained) is given preference, | ||
92 | i.e. the first column is used only for p >= 0.05. | ||
93 | */ | ||
25 | static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = { | 94 | static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = { |
26 | { 37172, 8172 }, | 95 | { 37172, 8172 }, |
27 | { 53499, 11567 }, | 96 | { 53499, 11567 }, |
@@ -525,85 +594,69 @@ static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = { | |||
525 | { 243315981, 271305 } | 594 | { 243315981, 271305 } |
526 | }; | 595 | }; |
527 | 596 | ||
528 | /* Calculate the send rate as per section 3.1 of RFC3448 | 597 | /* return largest index i such that fval <= lookup[i][small] */ |
529 | 598 | static inline u32 tfrc_binsearch(u32 fval, u8 small) | |
530 | Returns send rate in bytes per second | 599 | { |
531 | 600 | u32 try, low = 0, high = TFRC_CALC_X_ARRSIZE - 1; | |
532 | Integer maths and lookups are used as not allowed floating point in kernel | 601 | |
533 | 602 | while (low < high) { | |
534 | The function for Xcalc as per section 3.1 of RFC3448 is: | 603 | try = (low + high) / 2; |
535 | 604 | if (fval <= tfrc_calc_x_lookup[try][small]) | |
536 | X = s | 605 | high = try; |
537 | ------------------------------------------------------------- | 606 | else |
538 | R*sqrt(2*b*p/3) + (t_RTO * (3*sqrt(3*b*p/8) * p * (1+32*p^2))) | 607 | low = try + 1; |
539 | 608 | } | |
540 | where | 609 | return high; |
541 | X is the trasmit rate in bytes/second | 610 | } |
542 | s is the packet size in bytes | ||
543 | R is the round trip time in seconds | ||
544 | p is the loss event rate, between 0 and 1.0, of the number of loss events | ||
545 | as a fraction of the number of packets transmitted | ||
546 | t_RTO is the TCP retransmission timeout value in seconds | ||
547 | b is the number of packets acknowledged by a single TCP acknowledgement | ||
548 | |||
549 | we can assume that b = 1 and t_RTO is 4 * R. With this the equation becomes: | ||
550 | |||
551 | X = s | ||
552 | ----------------------------------------------------------------------- | ||
553 | R * sqrt(2 * p / 3) + (12 * R * (sqrt(3 * p / 8) * p * (1 + 32 * p^2))) | ||
554 | |||
555 | |||
556 | which we can break down into: | ||
557 | |||
558 | X = s | ||
559 | -------- | ||
560 | R * f(p) | ||
561 | |||
562 | where f(p) = sqrt(2 * p / 3) + (12 * sqrt(3 * p / 8) * p * (1 + 32 * p * p)) | ||
563 | |||
564 | Function parameters: | ||
565 | s - bytes | ||
566 | R - RTT in usecs | ||
567 | p - loss rate (decimal fraction multiplied by 1,000,000) | ||
568 | |||
569 | Returns Xcalc in bytes per second | ||
570 | |||
571 | DON'T alter this code unless you run test cases against it as the code | ||
572 | has been manipulated to stop underflow/overlow. | ||
573 | 611 | ||
574 | */ | 612 | /** |
613 | * tfrc_calc_x - Calculate the send rate as per section 3.1 of RFC3448 | ||
614 | * | ||
615 | * @s: packet size in bytes | ||
616 | * @R: RTT scaled by 1000000 (i.e., microseconds) | ||
617 | * @p: loss ratio estimate scaled by 1000000 | ||
618 | * Returns X_calc in bytes per second (not scaled). | ||
619 | * | ||
620 | * Note: DO NOT alter this code unless you run test cases against it, | ||
621 | * as the code has been optimized to stop underflow/overflow. | ||
622 | */ | ||
575 | u32 tfrc_calc_x(u16 s, u32 R, u32 p) | 623 | u32 tfrc_calc_x(u16 s, u32 R, u32 p) |
576 | { | 624 | { |
577 | int index; | 625 | int index; |
578 | u32 f; | 626 | u32 f; |
579 | u64 tmp1, tmp2; | 627 | u64 tmp1, tmp2; |
580 | 628 | ||
581 | if (p < TFRC_CALC_X_SPLIT) | 629 | /* check against invalid parameters and divide-by-zero */ |
582 | index = (p / (TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE)) - 1; | 630 | BUG_ON(p > 1000000); /* p must not exceed 100% */ |
583 | else | 631 | BUG_ON(p == 0); /* f(0) = 0, divide by zero */ |
584 | index = (p / (1000000 / TFRC_CALC_X_ARRSIZE)) - 1; | 632 | if (R == 0) { /* possible divide by zero */ |
633 | DCCP_CRIT("WARNING: RTT is 0, returning maximum X_calc."); | ||
634 | return ~0U; | ||
635 | } | ||
585 | 636 | ||
586 | if (index < 0) | 637 | if (p <= TFRC_CALC_X_SPLIT) { /* 0.0000 < p <= 0.05 */ |
587 | /* p should be 0 unless there is a bug in my code */ | 638 | if (p < TFRC_SMALLEST_P) { /* 0.0000 < p < 0.0001 */ |
588 | index = 0; | 639 | DCCP_WARN("Value of p (%d) below resolution. " |
640 | "Substituting %d\n", p, TFRC_SMALLEST_P); | ||
641 | index = 0; | ||
642 | } else /* 0.0001 <= p <= 0.05 */ | ||
643 | index = p/TFRC_SMALLEST_P - 1; | ||
589 | 644 | ||
590 | if (R == 0) { | 645 | f = tfrc_calc_x_lookup[index][1]; |
591 | DCCP_WARN("RTT==0, setting to 1\n"); | ||
592 | R = 1; /* RTT can't be zero or else divide by zero */ | ||
593 | } | ||
594 | 646 | ||
595 | BUG_ON(index >= TFRC_CALC_X_ARRSIZE); | 647 | } else { /* 0.05 < p <= 1.00 */ |
648 | index = p/(1000000/TFRC_CALC_X_ARRSIZE) - 1; | ||
596 | 649 | ||
597 | if (p >= TFRC_CALC_X_SPLIT) | ||
598 | f = tfrc_calc_x_lookup[index][0]; | 650 | f = tfrc_calc_x_lookup[index][0]; |
599 | else | 651 | } |
600 | f = tfrc_calc_x_lookup[index][1]; | ||
601 | 652 | ||
653 | /* The following computes X = s/(R*f(p)) in bytes per second. Since f(p) | ||
654 | * and R are both scaled by 1000000, we need to multiply by 1000000^2. | ||
655 | * ==> DO NOT alter this unless you test against overflow on 32 bit */ | ||
602 | tmp1 = ((u64)s * 100000000); | 656 | tmp1 = ((u64)s * 100000000); |
603 | tmp2 = ((u64)R * (u64)f); | 657 | tmp2 = ((u64)R * (u64)f); |
604 | do_div(tmp2, 10000); | 658 | do_div(tmp2, 10000); |
605 | do_div(tmp1, tmp2); | 659 | do_div(tmp1, tmp2); |
606 | /* Don't alter above math unless you test due to overflow on 32 bit */ | ||
607 | 660 | ||
608 | return (u32)tmp1; | 661 | return (u32)tmp1; |
609 | } | 662 | } |
@@ -611,33 +664,36 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p) | |||
611 | EXPORT_SYMBOL_GPL(tfrc_calc_x); | 664 | EXPORT_SYMBOL_GPL(tfrc_calc_x); |
612 | 665 | ||
613 | /* | 666 | /* |
614 | * args: fvalue - function value to match | 667 | * tfrc_calc_x_reverse_lookup - try to find p given f(p) |
615 | * returns: p closest to that value | ||
616 | * | 668 | * |
617 | * both fvalue and p are multiplied by 1,000,000 to use ints | 669 | * @fvalue: function value to match, scaled by 1000000 |
670 | * Returns closest match for p, also scaled by 1000000 | ||
618 | */ | 671 | */ |
619 | u32 tfrc_calc_x_reverse_lookup(u32 fvalue) | 672 | u32 tfrc_calc_x_reverse_lookup(u32 fvalue) |
620 | { | 673 | { |
621 | int ctr = 0; | 674 | int index; |
622 | int small; | ||
623 | 675 | ||
624 | if (fvalue < tfrc_calc_x_lookup[0][1]) | 676 | if (fvalue == 0) /* f(p) = 0 whenever p = 0 */ |
625 | return 0; | 677 | return 0; |
626 | 678 | ||
627 | if (fvalue <= tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][1]) | 679 | /* Error cases. */ |
628 | small = 1; | 680 | if (fvalue < tfrc_calc_x_lookup[0][1]) { |
629 | else if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) | 681 | DCCP_WARN("fvalue %d smaller than resolution\n", fvalue); |
682 | return tfrc_calc_x_lookup[0][1]; | ||
683 | } | ||
684 | if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) { | ||
685 | DCCP_WARN("fvalue %d exceeds bounds!\n", fvalue); | ||
630 | return 1000000; | 686 | return 1000000; |
631 | else | 687 | } |
632 | small = 0; | ||
633 | |||
634 | while (fvalue > tfrc_calc_x_lookup[ctr][small]) | ||
635 | ctr++; | ||
636 | 688 | ||
637 | if (small) | 689 | if (fvalue <= tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][1]) { |
638 | return TFRC_CALC_X_SPLIT * ctr / TFRC_CALC_X_ARRSIZE; | 690 | index = tfrc_binsearch(fvalue, 1); |
639 | else | 691 | return (index + 1) * TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE; |
640 | return 1000000 * ctr / TFRC_CALC_X_ARRSIZE; | 692 | } |
693 | |||
694 | /* else ... it must be in the coarse-grained column */ | ||
695 | index = tfrc_binsearch(fvalue, 0); | ||
696 | return (index + 1) * 1000000 / TFRC_CALC_X_ARRSIZE; | ||
641 | } | 697 | } |
642 | 698 | ||
643 | EXPORT_SYMBOL_GPL(tfrc_calc_x_reverse_lookup); | 699 | EXPORT_SYMBOL_GPL(tfrc_calc_x_reverse_lookup); |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 6f97665983d2..311205ffa775 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -858,7 +858,6 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, | |||
858 | int i; | 858 | int i; |
859 | 859 | ||
860 | xp->xfrm_nr = nr; | 860 | xp->xfrm_nr = nr; |
861 | xp->family = ut->family; | ||
862 | for (i = 0; i < nr; i++, ut++) { | 861 | for (i = 0; i < nr; i++, ut++) { |
863 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; | 862 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; |
864 | 863 | ||
@@ -876,19 +875,53 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, | |||
876 | } | 875 | } |
877 | } | 876 | } |
878 | 877 | ||
878 | static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) | ||
879 | { | ||
880 | int i; | ||
881 | |||
882 | if (nr > XFRM_MAX_DEPTH) | ||
883 | return -EINVAL; | ||
884 | |||
885 | for (i = 0; i < nr; i++) { | ||
886 | /* We never validated the ut->family value, so many | ||
887 | * applications simply leave it at zero. The check was | ||
888 | * never made and ut->family was ignored because all | ||
889 | * templates could be assumed to have the same family as | ||
890 | * the policy itself. Now that we will have ipv4-in-ipv6 | ||
891 | * and ipv6-in-ipv4 tunnels, this is no longer true. | ||
892 | */ | ||
893 | if (!ut[i].family) | ||
894 | ut[i].family = family; | ||
895 | |||
896 | switch (ut[i].family) { | ||
897 | case AF_INET: | ||
898 | break; | ||
899 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
900 | case AF_INET6: | ||
901 | break; | ||
902 | #endif | ||
903 | default: | ||
904 | return -EINVAL; | ||
905 | }; | ||
906 | } | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
879 | static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) | 911 | static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) |
880 | { | 912 | { |
881 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; | 913 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; |
882 | struct xfrm_user_tmpl *utmpl; | ||
883 | int nr; | ||
884 | 914 | ||
885 | if (!rt) { | 915 | if (!rt) { |
886 | pol->xfrm_nr = 0; | 916 | pol->xfrm_nr = 0; |
887 | } else { | 917 | } else { |
888 | nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); | 918 | struct xfrm_user_tmpl *utmpl = RTA_DATA(rt); |
919 | int nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); | ||
920 | int err; | ||
889 | 921 | ||
890 | if (nr > XFRM_MAX_DEPTH) | 922 | err = validate_tmpl(nr, utmpl, pol->family); |
891 | return -EINVAL; | 923 | if (err) |
924 | return err; | ||
892 | 925 | ||
893 | copy_templates(pol, RTA_DATA(rt), nr); | 926 | copy_templates(pol, RTA_DATA(rt), nr); |
894 | } | 927 | } |
@@ -1530,7 +1563,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xf | |||
1530 | } | 1563 | } |
1531 | 1564 | ||
1532 | /* build an XP */ | 1565 | /* build an XP */ |
1533 | xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); if (!xp) { | 1566 | xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); |
1567 | if (!xp) { | ||
1534 | kfree(x); | 1568 | kfree(x); |
1535 | return err; | 1569 | return err; |
1536 | } | 1570 | } |
@@ -1979,7 +2013,7 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, | |||
1979 | return NULL; | 2013 | return NULL; |
1980 | 2014 | ||
1981 | nr = ((len - sizeof(*p)) / sizeof(*ut)); | 2015 | nr = ((len - sizeof(*p)) / sizeof(*ut)); |
1982 | if (nr > XFRM_MAX_DEPTH) | 2016 | if (validate_tmpl(nr, ut, p->sel.family)) |
1983 | return NULL; | 2017 | return NULL; |
1984 | 2018 | ||
1985 | if (p->dir > XFRM_POLICY_OUT) | 2019 | if (p->dir > XFRM_POLICY_OUT) |