ftape-format.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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. #include <linux/string.h>
  24. #include <linux/errno.h>
  25. #include <linux/ftape.h>
  26. #include <linux/qic117.h>
  27. #include "../lowlevel/ftape-tracing.h"
  28. #include "../lowlevel/ftape-io.h"
  29. #include "../lowlevel/ftape-ctl.h"
  30. #include "../lowlevel/ftape-rw.h"
  31. #include "../lowlevel/ftape-ecc.h"
  32. #include "../lowlevel/ftape-bsm.h"
  33. #include "../lowlevel/ftape-format.h"
  34. #if defined(TESTING)
  35. #define FT_FMT_SEGS_PER_BUF 50
  36. #else
  37. #define FT_FMT_SEGS_PER_BUF (FT_BUFF_SIZE/(4*FT_SECTORS_PER_SEGMENT))
  38. #endif
  39. static spinlock_t ftape_format_lock;
  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. spin_lock_irqsave(&ftape_format_lock, flags);
  119. TRACE_CATCH(fdc_setup_formatting(head), restore_flags(flags));
  120. spin_unlock_irqrestore(&ftape_format_lock, 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. }