ftape-format.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (C) 1997 Claus-Justus Heine.
  3.  This program is free software; you can redistribute it and/or modify
  4.  it under the terms of the GNU General Public License as published by
  5.  the Free Software Foundation; either version 2, or (at your option)
  6.  any later version.
  7.  This program is distributed in the hope that it will be useful,
  8.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  GNU General Public License for more details.
  11.  You should have received a copy of the GNU General Public License
  12.  along with this program; see the file COPYING.  If not, write to
  13.  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  14.  *
  15.  * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-format.c,v $
  16.  * $Revision: 1.2.4.1 $
  17.  * $Date: 1997/11/14 16:05:39 $
  18.  *
  19.  *      This file contains the code to support formatting of floppy
  20.  *      tape cartridges with the QIC-40/80/3010/3020 floppy-tape
  21.  *      driver "ftape" for Linux.
  22.  */
  23.  
  24. #include <linux/string.h>
  25. #include <linux/errno.h>
  26. #include <linux/ftape.h>
  27. #include <linux/qic117.h>
  28. #include "../lowlevel/ftape-tracing.h"
  29. #include "../lowlevel/ftape-io.h"
  30. #include "../lowlevel/ftape-ctl.h"
  31. #include "../lowlevel/ftape-rw.h"
  32. #include "../lowlevel/ftape-ecc.h"
  33. #include "../lowlevel/ftape-bsm.h"
  34. #include "../lowlevel/ftape-format.h"
  35. #if defined(TESTING)
  36. #define FT_FMT_SEGS_PER_BUF 50
  37. #else
  38. #define FT_FMT_SEGS_PER_BUF (FT_BUFF_SIZE/(4*FT_SECTORS_PER_SEGMENT))
  39. #endif
  40. /*
  41.  *  first segment of the new buffer
  42.  */
  43. static int switch_segment;
  44. /*
  45.  *  at most 256 segments fit into one 32 kb buffer.  Even TR-1 cartridges have
  46.  *  more than this many segments per track, so better be careful.
  47.  *
  48.  *  buffer_struct *buff: buffer to store the formatting coordinates in
  49.  *  int  start: starting segment for this buffer.
  50.  *  int    spt: segments per track
  51.  *
  52.  *  Note: segment ids are relative to the start of the track here.
  53.  */
  54. static void setup_format_buffer(buffer_struct *buff, int start, int spt,
  55. __u8 gap3)
  56. {
  57. int to_do = spt - start;
  58. TRACE_FUN(ft_t_flow);
  59. if (to_do > FT_FMT_SEGS_PER_BUF) {
  60. to_do = FT_FMT_SEGS_PER_BUF;
  61. }
  62. buff->ptr          = buff->address;
  63. buff->remaining    = to_do * FT_SECTORS_PER_SEGMENT; /* # sectors */
  64. buff->bytes        = buff->remaining * 4; /* need 4 bytes per sector */
  65. buff->gap3         = gap3;
  66. buff->segment_id   = start;
  67. buff->next_segment = start + to_do;
  68. if (buff->next_segment >= spt) {
  69. buff->next_segment = 0; /* 0 means: stop runner */
  70. }
  71. buff->status       = waiting; /* tells the isr that it can use
  72.        * this buffer
  73.        */
  74. TRACE_EXIT;
  75. }
  76. /*
  77.  *  start formatting a new track.
  78.  */
  79. int ftape_format_track(const unsigned int track, const __u8 gap3)
  80. {
  81. unsigned long flags;
  82. buffer_struct *tail, *head;
  83. int status;
  84. TRACE_FUN(ft_t_flow);
  85. TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),);
  86. if (track & 1) {
  87. if (!(status & QIC_STATUS_AT_EOT)) {
  88. TRACE_CATCH(ftape_seek_to_eot(),);
  89. }
  90. } else {
  91. if (!(status & QIC_STATUS_AT_BOT)) {
  92. TRACE_CATCH(ftape_seek_to_bot(),);
  93. }
  94. }
  95. ftape_abort_operation(); /* this sets ft_head = ft_tail = 0 */
  96. ftape_set_state(formatting);
  97. TRACE(ft_t_noise,
  98.       "Formatting track %d, logical: from segment %d to %d",
  99.       track, track * ft_segments_per_track, 
  100.       (track + 1) * ft_segments_per_track - 1);
  101. /*
  102.  *  initialize the buffer switching protocol for this track
  103.  */
  104. head = ftape_get_buffer(ft_queue_head); /* tape isn't running yet */
  105. tail = ftape_get_buffer(ft_queue_tail); /* tape isn't running yet */
  106. switch_segment = 0;
  107. do {
  108. FT_SIGNAL_EXIT(_DONT_BLOCK);
  109. setup_format_buffer(tail, switch_segment,
  110.     ft_segments_per_track, gap3);
  111. switch_segment = tail->next_segment;
  112. } while ((switch_segment != 0) &&
  113.  ((tail = ftape_next_buffer(ft_queue_tail)) != head));
  114. /* go */
  115. head->status = formatting;
  116. TRACE_CATCH(ftape_seek_head_to_track(track),);
  117. TRACE_CATCH(ftape_command(QIC_LOGICAL_FORWARD),);
  118. save_flags(flags); cli();
  119. TRACE_CATCH(fdc_setup_formatting(head), restore_flags(flags));
  120. restore_flags(flags);
  121. TRACE_EXIT 0;
  122. }
  123. /*   return segment id of segment currently being formatted and do the
  124.  *   buffer switching stuff.
  125.  */
  126. int ftape_format_status(unsigned int *segment_id)
  127. {
  128. buffer_struct *tail = ftape_get_buffer(ft_queue_tail);
  129. int result;
  130. TRACE_FUN(ft_t_flow);
  131. while (switch_segment != 0 &&
  132.        ftape_get_buffer(ft_queue_head) != tail) {
  133. FT_SIGNAL_EXIT(_DONT_BLOCK);
  134. /*  need more buffers, first wait for empty buffer
  135.  */
  136. TRACE_CATCH(ftape_wait_segment(formatting),);
  137. /*  don't worry for gap3. If we ever hit this piece of code,
  138.  *  then all buffer already have the correct gap3 set!
  139.  */
  140. setup_format_buffer(tail, switch_segment,
  141.     ft_segments_per_track, tail->gap3);
  142. switch_segment = tail->next_segment;
  143. if (switch_segment != 0) {
  144. tail = ftape_next_buffer(ft_queue_tail);
  145. }
  146. }
  147. /*    should runner stop ?
  148.  */
  149. if (ft_runner_status == aborting || ft_runner_status == do_abort) {
  150. buffer_struct *head = ftape_get_buffer(ft_queue_head);
  151. TRACE(ft_t_warn, "Error formatting segment %d",
  152.       ftape_get_buffer(ft_queue_head)->segment_id);
  153. (void)ftape_abort_operation();
  154. TRACE_EXIT (head->status != error) ? -EAGAIN : -EIO;
  155. }
  156. /*
  157.  *  don't care if the timer expires, this is just kind of a
  158.  *  "select" operation that lets the calling process sleep
  159.  *  until something has happened
  160.  */
  161. if (fdc_interrupt_wait(5 * FT_SECOND) < 0) {
  162. TRACE(ft_t_noise, "End of track %d at segment %d",
  163.       ft_location.track,
  164.       ftape_get_buffer(ft_queue_head)->segment_id);
  165. result = 1;  /* end of track, unlock module */
  166. } else {
  167. result = 0;
  168. }
  169. /*
  170.  *  the calling process should use the seg id to determine
  171.  *  which parts of the dma buffers can be safely overwritten
  172.  *  with new data.
  173.  */
  174. *segment_id = ftape_get_buffer(ft_queue_head)->segment_id;
  175. /*
  176.  *  Internally we start counting segment ids from the start of
  177.  *  each track when formatting, but externally we keep them
  178.  *  relative to the start of the tape:
  179.  */
  180. *segment_id += ft_location.track * ft_segments_per_track;
  181. TRACE_EXIT result;
  182. }
  183. /*
  184.  *  The segment id is relative to the start of the tape
  185.  */
  186. int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm)
  187. {
  188. int result;
  189. int verify_done = 0;
  190. TRACE_FUN(ft_t_flow);
  191. TRACE(ft_t_noise, "Verifying segment %d", segment_id);
  192. if (ft_driver_state != verifying) {
  193. TRACE(ft_t_noise, "calling ftape_abort_operation");
  194. if (ftape_abort_operation() < 0) {
  195. TRACE(ft_t_err, "ftape_abort_operation failed");
  196. TRACE_EXIT -EIO;
  197. }
  198. }
  199. *bsm = 0x00000000;
  200. ftape_set_state(verifying);
  201. for (;;) {
  202. buffer_struct *tail;
  203. /*
  204.  *  Allow escape from this loop on signal
  205.  */
  206. FT_SIGNAL_EXIT(_DONT_BLOCK);
  207. /*
  208.  *  Search all full buffers for the first matching the
  209.  *  wanted segment.  Clear other buffers on the fly.
  210.  */
  211. tail = ftape_get_buffer(ft_queue_tail);
  212. while (!verify_done && tail->status == done) {
  213. /*
  214.  *  Allow escape from this loop on signal !
  215.  */
  216. FT_SIGNAL_EXIT(_DONT_BLOCK);
  217. if (tail->segment_id == segment_id) {
  218. /*  If out buffer is already full,
  219.  *  return its contents.  
  220.  */
  221. TRACE(ft_t_flow, "found segment in cache: %d",
  222.       segment_id);
  223. if ((tail->soft_error_map |
  224.      tail->hard_error_map) != 0) {
  225. TRACE(ft_t_info,"bsm[%d] = 0x%08lx",
  226.       segment_id,
  227.       (unsigned long)
  228.       (tail->soft_error_map |
  229.       tail->hard_error_map));
  230. *bsm = (tail->soft_error_map |
  231. tail->hard_error_map);
  232. }
  233. verify_done = 1;
  234. } else {
  235. TRACE(ft_t_flow,"zapping segment in cache: %d",
  236.       tail->segment_id);
  237. }
  238. tail->status = waiting;
  239. tail = ftape_next_buffer(ft_queue_tail);
  240. }
  241. if (!verify_done && tail->status == verifying) {
  242. if (tail->segment_id == segment_id) {
  243. switch(ftape_wait_segment(verifying)) {
  244. case 0:
  245. break;
  246. case -EINTR:
  247. TRACE_ABORT(-EINTR, ft_t_warn,
  248.     "interrupted by "
  249.     "non-blockable signal");
  250. break;
  251. default:
  252. ftape_abort_operation();
  253. ftape_set_state(verifying);
  254. /* be picky */
  255. TRACE_ABORT(-EIO, ft_t_warn,
  256.     "wait_segment failed");
  257. }
  258. } else {
  259. /*  We're reading the wrong segment,
  260.  *  stop runner.
  261.  */
  262. TRACE(ft_t_noise, "verifying wrong segment");
  263. ftape_abort_operation();
  264. ftape_set_state(verifying);
  265. }
  266. }
  267. /*    should runner stop ?
  268.  */
  269. if (ft_runner_status == aborting) {
  270. buffer_struct *head = ftape_get_buffer(ft_queue_head);
  271. if (head->status == error ||
  272.     head->status == verifying) {
  273. /* no data or overrun error */
  274. head->status = waiting;
  275. }
  276. TRACE_CATCH(ftape_dumb_stop(),);
  277. } else {
  278. /*  If just passed last segment on tape: wait
  279.  *  for BOT or EOT mark. Sets ft_runner_status to
  280.  *  idle if at lEOT and successful 
  281.  */
  282. TRACE_CATCH(ftape_handle_logical_eot(),);
  283. }
  284. if (verify_done) {
  285. TRACE_EXIT 0;
  286. }
  287. /*    Now at least one buffer is idle!
  288.  *    Restart runner & tape if needed.
  289.  */
  290. /*  We could optimize the following a little bit. We know that 
  291.  *  the bad sector map is empty.
  292.  */
  293. tail = ftape_get_buffer(ft_queue_tail);
  294. if (tail->status == waiting) {
  295. buffer_struct *head = ftape_get_buffer(ft_queue_head);
  296. ftape_setup_new_segment(head, segment_id, -1);
  297. ftape_calc_next_cluster(head);
  298. if (ft_runner_status == idle) {
  299. result = ftape_start_tape(segment_id,
  300.   head->sector_offset);
  301. switch(result) {
  302. case 0:
  303. break;
  304. case -ETIME:
  305. case -EINTR:
  306. TRACE_ABORT(result, ft_t_err, "Error: "
  307.     "segment %d unreachable",
  308.     segment_id);
  309. break;
  310. default:
  311. *bsm = EMPTY_SEGMENT;
  312. TRACE_EXIT 0;
  313. break;
  314. }
  315. }
  316. head->status = verifying;
  317. fdc_setup_read_write(head, FDC_VERIFY);
  318. }
  319. }
  320. /* not reached */
  321. TRACE_EXIT -EIO;
  322. }