Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 }
345 
  This page was automatically generated by the LXR engine.