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: /home/user/PROJECT/WL-520gu-NewUI/src/linux/linux/drivers/char/ftape/lowlevel/ftape-format.c,v $ 20 * $Revision: 1.1.1.1 $ 21 * $Date: 2008/10/15 03:26:29 $ 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/* 48 * first segment of the new buffer 49 */ 50static int switch_segment; 51 52/* 53 * at most 256 segments fit into one 32 kb buffer. Even TR-1 cartridges have 54 * more than this many segments per track, so better be careful. 55 * 56 * buffer_struct *buff: buffer to store the formatting coordinates in 57 * int start: starting segment for this buffer. 58 * int spt: segments per track 59 * 60 * Note: segment ids are relative to the start of the track here. 61 */ 62static void setup_format_buffer(buffer_struct *buff, int start, int spt, 63 __u8 gap3) 64{ 65 int to_do = spt - start; 66 TRACE_FUN(ft_t_flow); 67 68 if (to_do > FT_FMT_SEGS_PER_BUF) { 69 to_do = FT_FMT_SEGS_PER_BUF; 70 } 71 buff->ptr = buff->address; 72 buff->remaining = to_do * FT_SECTORS_PER_SEGMENT; /* # sectors */ 73 buff->bytes = buff->remaining * 4; /* need 4 bytes per sector */ 74 buff->gap3 = gap3; 75 buff->segment_id = start; 76 buff->next_segment = start + to_do; 77 if (buff->next_segment >= spt) { 78 buff->next_segment = 0; /* 0 means: stop runner */ 79 } 80 buff->status = waiting; /* tells the isr that it can use 81 * this buffer 82 */ 83 TRACE_EXIT; 84} 85 86 87/* 88 * start formatting a new track. 89 */ 90int ftape_format_track(const unsigned int track, const __u8 gap3) 91{ 92 unsigned long flags; 93 buffer_struct *tail, *head; 94 int status; 95 TRACE_FUN(ft_t_flow); 96 97 TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); 98 if (track & 1) { 99 if (!(status & QIC_STATUS_AT_EOT)) { 100 TRACE_CATCH(ftape_seek_to_eot(),); 101 } 102 } else { 103 if (!(status & QIC_STATUS_AT_BOT)) { 104 TRACE_CATCH(ftape_seek_to_bot(),); 105 } 106 } 107 ftape_abort_operation(); /* this sets ft_head = ft_tail = 0 */ 108 ftape_set_state(formatting); 109 110 TRACE(ft_t_noise, 111 "Formatting track %d, logical: from segment %d to %d", 112 track, track * ft_segments_per_track, 113 (track + 1) * ft_segments_per_track - 1); 114 115 /* 116 * initialize the buffer switching protocol for this track 117 */ 118 head = ftape_get_buffer(ft_queue_head); /* tape isn't running yet */ 119 tail = ftape_get_buffer(ft_queue_tail); /* tape isn't running yet */ 120 switch_segment = 0; 121 do { 122 FT_SIGNAL_EXIT(_DONT_BLOCK); 123 setup_format_buffer(tail, switch_segment, 124 ft_segments_per_track, gap3); 125 switch_segment = tail->next_segment; 126 } while ((switch_segment != 0) && 127 ((tail = ftape_next_buffer(ft_queue_tail)) != head)); 128 /* go */ 129 head->status = formatting; 130 TRACE_CATCH(ftape_seek_head_to_track(track),); 131 TRACE_CATCH(ftape_command(QIC_LOGICAL_FORWARD),); 132 save_flags(flags); cli(); 133 TRACE_CATCH(fdc_setup_formatting(head), restore_flags(flags)); 134 restore_flags(flags); 135 TRACE_EXIT 0; 136} 137 138/* return segment id of segment currently being formatted and do the 139 * buffer switching stuff. 140 */ 141int ftape_format_status(unsigned int *segment_id) 142{ 143 buffer_struct *tail = ftape_get_buffer(ft_queue_tail); 144 int result; 145 TRACE_FUN(ft_t_flow); 146 147 while (switch_segment != 0 && 148 ftape_get_buffer(ft_queue_head) != tail) { 149 FT_SIGNAL_EXIT(_DONT_BLOCK); 150 /* need more buffers, first wait for empty buffer 151 */ 152 TRACE_CATCH(ftape_wait_segment(formatting),); 153 /* don't worry for gap3. If we ever hit this piece of code, 154 * then all buffer already have the correct gap3 set! 155 */ 156 setup_format_buffer(tail, switch_segment, 157 ft_segments_per_track, tail->gap3); 158 switch_segment = tail->next_segment; 159 if (switch_segment != 0) { 160 tail = ftape_next_buffer(ft_queue_tail); 161 } 162 } 163 /* should runner stop ? 164 */ 165 if (ft_runner_status == aborting || ft_runner_status == do_abort) { 166 buffer_struct *head = ftape_get_buffer(ft_queue_head); 167 TRACE(ft_t_warn, "Error formatting segment %d", 168 ftape_get_buffer(ft_queue_head)->segment_id); 169 (void)ftape_abort_operation(); 170 TRACE_EXIT (head->status != error) ? -EAGAIN : -EIO; 171 } 172 /* 173 * don't care if the timer expires, this is just kind of a 174 * "select" operation that lets the calling process sleep 175 * until something has happened 176 */ 177 if (fdc_interrupt_wait(5 * FT_SECOND) < 0) { 178 TRACE(ft_t_noise, "End of track %d at segment %d", 179 ft_location.track, 180 ftape_get_buffer(ft_queue_head)->segment_id); 181 result = 1; /* end of track, unlock module */ 182 } else { 183 result = 0; 184 } 185 /* 186 * the calling process should use the seg id to determine 187 * which parts of the dma buffers can be safely overwritten 188 * with new data. 189 */ 190 *segment_id = ftape_get_buffer(ft_queue_head)->segment_id; 191 /* 192 * Internally we start counting segment ids from the start of 193 * each track when formatting, but externally we keep them 194 * relative to the start of the tape: 195 */ 196 *segment_id += ft_location.track * ft_segments_per_track; 197 TRACE_EXIT result; 198} 199 200/* 201 * The segment id is relative to the start of the tape 202 */ 203int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm) 204{ 205 int result; 206 int verify_done = 0; 207 TRACE_FUN(ft_t_flow); 208 209 TRACE(ft_t_noise, "Verifying segment %d", segment_id); 210 211 if (ft_driver_state != verifying) { 212 TRACE(ft_t_noise, "calling ftape_abort_operation"); 213 if (ftape_abort_operation() < 0) { 214 TRACE(ft_t_err, "ftape_abort_operation failed"); 215 TRACE_EXIT -EIO; 216 } 217 } 218 *bsm = 0x00000000; 219 ftape_set_state(verifying); 220 for (;;) { 221 buffer_struct *tail; 222 /* 223 * Allow escape from this loop on signal 224 */ 225 FT_SIGNAL_EXIT(_DONT_BLOCK); 226 /* 227 * Search all full buffers for the first matching the 228 * wanted segment. Clear other buffers on the fly. 229 */ 230 tail = ftape_get_buffer(ft_queue_tail); 231 while (!verify_done && tail->status == done) { 232 /* 233 * Allow escape from this loop on signal ! 234 */ 235 FT_SIGNAL_EXIT(_DONT_BLOCK); 236 if (tail->segment_id == segment_id) { 237 /* If out buffer is already full, 238 * return its contents. 239 */ 240 TRACE(ft_t_flow, "found segment in cache: %d", 241 segment_id); 242 if ((tail->soft_error_map | 243 tail->hard_error_map) != 0) { 244 TRACE(ft_t_info,"bsm[%d] = 0x%08lx", 245 segment_id, 246 (unsigned long) 247 (tail->soft_error_map | 248 tail->hard_error_map)); 249 *bsm = (tail->soft_error_map | 250 tail->hard_error_map); 251 } 252 verify_done = 1; 253 } else { 254 TRACE(ft_t_flow,"zapping segment in cache: %d", 255 tail->segment_id); 256 } 257 tail->status = waiting; 258 tail = ftape_next_buffer(ft_queue_tail); 259 } 260 if (!verify_done && tail->status == verifying) { 261 if (tail->segment_id == segment_id) { 262 switch(ftape_wait_segment(verifying)) { 263 case 0: 264 break; 265 case -EINTR: 266 TRACE_ABORT(-EINTR, ft_t_warn, 267 "interrupted by " 268 "non-blockable signal"); 269 break; 270 default: 271 ftape_abort_operation(); 272 ftape_set_state(verifying); 273 /* be picky */ 274 TRACE_ABORT(-EIO, ft_t_warn, 275 "wait_segment failed"); 276 } 277 } else { 278 /* We're reading the wrong segment, 279 * stop runner. 280 */ 281 TRACE(ft_t_noise, "verifying wrong segment"); 282 ftape_abort_operation(); 283 ftape_set_state(verifying); 284 } 285 } 286 /* should runner stop ? 287 */ 288 if (ft_runner_status == aborting) { 289 buffer_struct *head = ftape_get_buffer(ft_queue_head); 290 if (head->status == error || 291 head->status == verifying) { 292 /* no data or overrun error */ 293 head->status = waiting; 294 } 295 TRACE_CATCH(ftape_dumb_stop(),); 296 } else { 297 /* If just passed last segment on tape: wait 298 * for BOT or EOT mark. Sets ft_runner_status to 299 * idle if at lEOT and successful 300 */ 301 TRACE_CATCH(ftape_handle_logical_eot(),); 302 } 303 if (verify_done) { 304 TRACE_EXIT 0; 305 } 306 /* Now at least one buffer is idle! 307 * Restart runner & tape if needed. 308 */ 309 /* We could optimize the following a little bit. We know that 310 * the bad sector map is empty. 311 */ 312 tail = ftape_get_buffer(ft_queue_tail); 313 if (tail->status == waiting) { 314 buffer_struct *head = ftape_get_buffer(ft_queue_head); 315 316 ftape_setup_new_segment(head, segment_id, -1); 317 ftape_calc_next_cluster(head); 318 if (ft_runner_status == idle) { 319 result = ftape_start_tape(segment_id, 320 head->sector_offset); 321 switch(result) { 322 case 0: 323 break; 324 case -ETIME: 325 case -EINTR: 326 TRACE_ABORT(result, ft_t_err, "Error: " 327 "segment %d unreachable", 328 segment_id); 329 break; 330 default: 331 *bsm = EMPTY_SEGMENT; 332 TRACE_EXIT 0; 333 break; 334 } 335 } 336 head->status = verifying; 337 fdc_setup_read_write(head, FDC_VERIFY); 338 } 339 } 340 /* not reached */ 341 TRACE_EXIT -EIO; 342} 343