Linux-2.6.12-rc2
[linux-2.6/kvm.git] / drivers / char / ftape / lowlevel / ftape-format.c
blob5dd4c59a3f34903a27d4c98821ea7dcefdf75337
1 /*
2 * Copyright (C) 1997 Claus-Justus Heine.
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.
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.
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.
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 $
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.
28 #include <linux/string.h>
29 #include <linux/errno.h>
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"
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
47 static spinlock_t ftape_format_lock;
50 * first segment of the new buffer
52 static int switch_segment;
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.
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
62 * Note: segment ids are relative to the start of the track here.
64 static void setup_format_buffer(buffer_struct *buff, int start, int spt,
65 __u8 gap3)
67 int to_do = spt - start;
68 TRACE_FUN(ft_t_flow);
70 if (to_do > FT_FMT_SEGS_PER_BUF) {
71 to_do = FT_FMT_SEGS_PER_BUF;
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 */
82 buff->status = waiting; /* tells the isr that it can use
83 * this buffer
85 TRACE_EXIT;
90 * start formatting a new track.
92 int ftape_format_track(const unsigned int track, const __u8 gap3)
94 unsigned long flags;
95 buffer_struct *tail, *head;
96 int status;
97 TRACE_FUN(ft_t_flow);
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(),);
104 } else {
105 if (!(status & QIC_STATUS_AT_BOT)) {
106 TRACE_CATCH(ftape_seek_to_bot(),);
109 ftape_abort_operation(); /* this sets ft_head = ft_tail = 0 */
110 ftape_set_state(formatting);
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);
118 * initialize the buffer switching protocol for this track
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;
140 /* return segment id of segment currently being formatted and do the
141 * buffer switching stuff.
143 int ftape_format_status(unsigned int *segment_id)
145 buffer_struct *tail = ftape_get_buffer(ft_queue_tail);
146 int result;
147 TRACE_FUN(ft_t_flow);
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
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!
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);
165 /* should runner stop ?
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;
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
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;
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.
192 *segment_id = ftape_get_buffer(ft_queue_head)->segment_id;
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:
198 *segment_id += ft_location.track * ft_segments_per_track;
199 TRACE_EXIT result;
203 * The segment id is relative to the start of the tape
205 int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm)
207 int result;
208 int verify_done = 0;
209 TRACE_FUN(ft_t_flow);
211 TRACE(ft_t_noise, "Verifying segment %d", segment_id);
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;
220 *bsm = 0x00000000;
221 ftape_set_state(verifying);
222 for (;;) {
223 buffer_struct *tail;
225 * Allow escape from this loop on signal
227 FT_SIGNAL_EXIT(_DONT_BLOCK);
229 * Search all full buffers for the first matching the
230 * wanted segment. Clear other buffers on the fly.
232 tail = ftape_get_buffer(ft_queue_tail);
233 while (!verify_done && tail->status == done) {
235 * Allow escape from this loop on signal !
237 FT_SIGNAL_EXIT(_DONT_BLOCK);
238 if (tail->segment_id == segment_id) {
239 /* If out buffer is already full,
240 * return its contents.
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);
254 verify_done = 1;
255 } else {
256 TRACE(ft_t_flow,"zapping segment in cache: %d",
257 tail->segment_id);
259 tail->status = waiting;
260 tail = ftape_next_buffer(ft_queue_tail);
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");
279 } else {
280 /* We're reading the wrong segment,
281 * stop runner.
283 TRACE(ft_t_noise, "verifying wrong segment");
284 ftape_abort_operation();
285 ftape_set_state(verifying);
288 /* should runner stop ?
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;
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
303 TRACE_CATCH(ftape_handle_logical_eot(),);
305 if (verify_done) {
306 TRACE_EXIT 0;
308 /* Now at least one buffer is idle!
309 * Restart runner & tape if needed.
311 /* We could optimize the following a little bit. We know that
312 * the bad sector map is empty.
314 tail = ftape_get_buffer(ft_queue_tail);
315 if (tail->status == waiting) {
316 buffer_struct *head = ftape_get_buffer(ft_queue_head);
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;
338 head->status = verifying;
339 fdc_setup_read_write(head, FDC_VERIFY);
342 /* not reached */
343 TRACE_EXIT -EIO;