ftape-write.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. * Copyright (C) 1993-1995 Bas Laarhoven,
  3. * (C) 1996-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.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; see the file COPYING. If not, write to
  14. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  15. *
  16. * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-write.c,v $
  17. * $Revision: 1.3.4.1 $
  18. * $Date: 1997/11/14 18:07:04 $
  19. *
  20. * This file contains the writing code
  21. * for the QIC-117 floppy-tape driver for Linux.
  22. */
  23. #include <linux/string.h>
  24. #include <linux/errno.h>
  25. #include <linux/mm.h>
  26. #include <linux/ftape.h>
  27. #include <linux/qic117.h>
  28. #include "../lowlevel/ftape-tracing.h"
  29. #include "../lowlevel/ftape-write.h"
  30. #include "../lowlevel/ftape-read.h"
  31. #include "../lowlevel/ftape-io.h"
  32. #include "../lowlevel/ftape-ctl.h"
  33. #include "../lowlevel/ftape-rw.h"
  34. #include "../lowlevel/ftape-ecc.h"
  35. #include "../lowlevel/ftape-bsm.h"
  36. #include "../lowlevel/fdc-isr.h"
  37. /* Global vars.
  38. */
  39. /* Local vars.
  40. */
  41. static int last_write_failed;
  42. void ftape_zap_write_buffers(void)
  43. {
  44. int i;
  45. for (i = 0; i < ft_nr_buffers; ++i) {
  46. ft_buffer[i]->status = done;
  47. }
  48. ftape_reset_buffer();
  49. }
  50. static int copy_and_gen_ecc(void *destination,
  51. const void *source,
  52. const SectorMap bad_sector_map)
  53. {
  54. int result;
  55. struct memory_segment mseg;
  56. int bads = count_ones(bad_sector_map);
  57. TRACE_FUN(ft_t_any);
  58. if (bads > 0) {
  59. TRACE(ft_t_noise, "bad sectors in map: %d", bads);
  60. }
  61. if (bads + 3 >= FT_SECTORS_PER_SEGMENT) {
  62. TRACE(ft_t_noise, "empty segment");
  63. mseg.blocks = 0; /* skip entire segment */
  64. result = 0; /* nothing written */
  65. } else {
  66. mseg.blocks = FT_SECTORS_PER_SEGMENT - bads;
  67. mseg.data = destination;
  68. memcpy(mseg.data, source, (mseg.blocks - 3) * FT_SECTOR_SIZE);
  69. result = ftape_ecc_set_segment_parity(&mseg);
  70. if (result < 0) {
  71. TRACE(ft_t_err, "ecc_set_segment_parity failed");
  72. } else {
  73. result = (mseg.blocks - 3) * FT_SECTOR_SIZE;
  74. }
  75. }
  76. TRACE_EXIT result;
  77. }
  78. int ftape_start_writing(const ft_write_mode_t mode)
  79. {
  80. buffer_struct *head = ftape_get_buffer(ft_queue_head);
  81. int segment_id = head->segment_id;
  82. int result;
  83. buffer_state_enum wanted_state = (mode == FT_WR_DELETE
  84. ? deleting
  85. : writing);
  86. TRACE_FUN(ft_t_flow);
  87. if ((ft_driver_state != wanted_state) || head->status != waiting) {
  88. TRACE_EXIT 0;
  89. }
  90. ftape_setup_new_segment(head, segment_id, 1);
  91. if (mode == FT_WR_SINGLE) {
  92. /* stop tape instead of pause */
  93. head->next_segment = 0;
  94. }
  95. ftape_calc_next_cluster(head); /* prepare */
  96. head->status = ft_driver_state; /* either writing or deleting */
  97. if (ft_runner_status == idle) {
  98. TRACE(ft_t_noise,
  99. "starting runner for segment %d", segment_id);
  100. TRACE_CATCH(ftape_start_tape(segment_id,head->sector_offset),);
  101. } else {
  102. TRACE(ft_t_noise, "runner not idle, not starting tape");
  103. }
  104. /* go */
  105. result = fdc_setup_read_write(head, (mode == FT_WR_DELETE
  106. ? FDC_WRITE_DELETED : FDC_WRITE));
  107. ftape_set_state(wanted_state); /* should not be necessary */
  108. TRACE_EXIT result;
  109. }
  110. /* Wait until all data is actually written to tape.
  111. *
  112. * There is a problem: when the tape runs into logical EOT, then this
  113. * failes. We need to restart the runner in this case.
  114. */
  115. int ftape_loop_until_writes_done(void)
  116. {
  117. buffer_struct *head;
  118. TRACE_FUN(ft_t_flow);
  119. while ((ft_driver_state == writing || ft_driver_state == deleting) &&
  120. ftape_get_buffer(ft_queue_head)->status != done) {
  121. /* set the runner status to idle if at lEOT */
  122. TRACE_CATCH(ftape_handle_logical_eot(), last_write_failed = 1);
  123. /* restart the tape if necessary */
  124. if (ft_runner_status == idle) {
  125. TRACE(ft_t_noise, "runner is idle, restarting");
  126. if (ft_driver_state == deleting) {
  127. TRACE_CATCH(ftape_start_writing(FT_WR_DELETE),
  128. last_write_failed = 1);
  129. } else {
  130. TRACE_CATCH(ftape_start_writing(FT_WR_MULTI),
  131. last_write_failed = 1);
  132. }
  133. }
  134. TRACE(ft_t_noise, "tail: %d, head: %d",
  135. ftape_buffer_id(ft_queue_tail),
  136. ftape_buffer_id(ft_queue_head));
  137. TRACE_CATCH(fdc_interrupt_wait(5 * FT_SECOND),
  138. last_write_failed = 1);
  139. head = ftape_get_buffer(ft_queue_head);
  140. if (head->status == error) {
  141. /* Allow escape from loop when signaled !
  142. */
  143. FT_SIGNAL_EXIT(_DONT_BLOCK);
  144. if (head->hard_error_map != 0) {
  145. /* Implement hard write error recovery here
  146. */
  147. }
  148. /* retry this one */
  149. head->status = waiting;
  150. if (ft_runner_status == aborting) {
  151. ftape_dumb_stop();
  152. }
  153. if (ft_runner_status != idle) {
  154. TRACE_ABORT(-EIO, ft_t_err,
  155. "unexpected state: "
  156. "ft_runner_status != idle");
  157. }
  158. ftape_start_writing(ft_driver_state == deleting
  159. ? FT_WR_MULTI : FT_WR_DELETE);
  160. }
  161. TRACE(ft_t_noise, "looping until writes done");
  162. }
  163. ftape_set_state(idle);
  164. TRACE_EXIT 0;
  165. }
  166. /* Write given segment from buffer at address to tape.
  167. */
  168. static int write_segment(const int segment_id,
  169. const void *address,
  170. const ft_write_mode_t write_mode)
  171. {
  172. int bytes_written = 0;
  173. buffer_struct *tail;
  174. buffer_state_enum wanted_state = (write_mode == FT_WR_DELETE
  175. ? deleting : writing);
  176. TRACE_FUN(ft_t_flow);
  177. TRACE(ft_t_noise, "segment_id = %d", segment_id);
  178. if (ft_driver_state != wanted_state) {
  179. if (ft_driver_state == deleting ||
  180. wanted_state == deleting) {
  181. TRACE_CATCH(ftape_loop_until_writes_done(),);
  182. }
  183. TRACE(ft_t_noise, "calling ftape_abort_operation");
  184. TRACE_CATCH(ftape_abort_operation(),);
  185. ftape_zap_write_buffers();
  186. ftape_set_state(wanted_state);
  187. }
  188. /* if all buffers full we'll have to wait...
  189. */
  190. ftape_wait_segment(wanted_state);
  191. tail = ftape_get_buffer(ft_queue_tail);
  192. switch(tail->status) {
  193. case done:
  194. ft_history.defects += count_ones(tail->hard_error_map);
  195. break;
  196. case waiting:
  197. /* this could happen with multiple EMPTY_SEGMENTs, but
  198. * shouldn't happen any more as we re-start the runner even
  199. * with an empty segment.
  200. */
  201. bytes_written = -EAGAIN;
  202. break;
  203. case error:
  204. /* setup for a retry
  205. */
  206. tail->status = waiting;
  207. bytes_written = -EAGAIN; /* force retry */
  208. if (tail->hard_error_map != 0) {
  209. TRACE(ft_t_warn,
  210. "warning: %d hard error(s) in written segment",
  211. count_ones(tail->hard_error_map));
  212. TRACE(ft_t_noise, "hard_error_map = 0x%08lx",
  213. (long)tail->hard_error_map);
  214. /* Implement hard write error recovery here
  215. */
  216. }
  217. break;
  218. default:
  219. TRACE_ABORT(-EIO, ft_t_err,
  220. "wait for empty segment failed, tail status: %d",
  221. tail->status);
  222. }
  223. /* should runner stop ?
  224. */
  225. if (ft_runner_status == aborting) {
  226. buffer_struct *head = ftape_get_buffer(ft_queue_head);
  227. if (head->status == wanted_state) {
  228. head->status = done; /* ???? */
  229. }
  230. /* don't call abort_operation(), we don't want to zap
  231. * the dma buffers
  232. */
  233. TRACE_CATCH(ftape_dumb_stop(),);
  234. } else {
  235. /* If just passed last segment on tape: wait for BOT
  236. * or EOT mark. Sets ft_runner_status to idle if at lEOT
  237. * and successful
  238. */
  239. TRACE_CATCH(ftape_handle_logical_eot(),);
  240. }
  241. if (tail->status == done) {
  242. /* now at least one buffer is empty, fill it with our
  243. * data. skip bad sectors and generate ecc.
  244. * copy_and_gen_ecc return nr of bytes written, range
  245. * 0..29 Kb inclusive!
  246. *
  247. * Empty segments are handled inside coyp_and_gen_ecc()
  248. */
  249. if (write_mode != FT_WR_DELETE) {
  250. TRACE_CATCH(bytes_written = copy_and_gen_ecc(
  251. tail->address, address,
  252. ftape_get_bad_sector_entry(segment_id)),);
  253. }
  254. tail->segment_id = segment_id;
  255. tail->status = waiting;
  256. tail = ftape_next_buffer(ft_queue_tail);
  257. }
  258. /* Start tape only if all buffers full or flush mode.
  259. * This will give higher probability of streaming.
  260. */
  261. if (ft_runner_status != running &&
  262. ((tail->status == waiting &&
  263. ftape_get_buffer(ft_queue_head) == tail) ||
  264. write_mode != FT_WR_ASYNC)) {
  265. TRACE_CATCH(ftape_start_writing(write_mode),);
  266. }
  267. TRACE_EXIT bytes_written;
  268. }
  269. /* Write as much as fits from buffer to the given segment on tape
  270. * and handle retries.
  271. * Return the number of bytes written (>= 0), or:
  272. * -EIO write failed
  273. * -EINTR interrupted by signal
  274. * -ENOSPC device full
  275. */
  276. int ftape_write_segment(const int segment_id,
  277. const void *buffer,
  278. const ft_write_mode_t flush)
  279. {
  280. int retry = 0;
  281. int result;
  282. TRACE_FUN(ft_t_flow);
  283. ft_history.used |= 2;
  284. if (segment_id >= ft_tracks_per_tape*ft_segments_per_track) {
  285. /* tape full */
  286. TRACE_ABORT(-ENOSPC, ft_t_err,
  287. "invalid segment id: %d (max %d)",
  288. segment_id,
  289. ft_tracks_per_tape * ft_segments_per_track -1);
  290. }
  291. for (;;) {
  292. if ((result = write_segment(segment_id, buffer, flush)) >= 0) {
  293. if (result == 0) { /* empty segment */
  294. TRACE(ft_t_noise,
  295. "empty segment, nothing written");
  296. }
  297. TRACE_EXIT result;
  298. }
  299. if (result == -EAGAIN) {
  300. if (++retry > 100) { /* give up */
  301. TRACE_ABORT(-EIO, ft_t_err,
  302. "write failed, >100 retries in segment");
  303. }
  304. TRACE(ft_t_warn, "write error, retry %d (%d)",
  305. retry,
  306. ftape_get_buffer(ft_queue_tail)->segment_id);
  307. } else {
  308. TRACE_ABORT(result, ft_t_err,
  309. "write_segment failed, error: %d", result);
  310. }
  311. /* Allow escape from loop when signaled !
  312. */
  313. FT_SIGNAL_EXIT(_DONT_BLOCK);
  314. }
  315. }