ftape-bsm.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. /*
  2. * Copyright (C) 1994-1996 Bas Laarhoven,
  3. * (C) 1996-1997 Claus 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-bsm.c,v $
  17. * $Revision: 1.3 $
  18. * $Date: 1997/10/05 19:15:15 $
  19. *
  20. * This file contains the bad-sector map handling code for
  21. * the QIC-117 floppy tape driver for Linux.
  22. * QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented.
  23. */
  24. #include <linux/string.h>
  25. #include <linux/ftape.h>
  26. #include "../lowlevel/ftape-tracing.h"
  27. #include "../lowlevel/ftape-bsm.h"
  28. #include "../lowlevel/ftape-ctl.h"
  29. #include "../lowlevel/ftape-rw.h"
  30. /* Global vars.
  31. */
  32. /* Local vars.
  33. */
  34. static __u8 *bad_sector_map;
  35. static SectorCount *bsm_hash_ptr;
  36. typedef enum {
  37. forward, backward
  38. } mode_type;
  39. #if 0
  40. static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map);
  41. #endif
  42. #if 0
  43. /* fix_tape converts a normal QIC-80 tape into a 'wide' tape.
  44. * For testing purposes only !
  45. */
  46. void fix_tape(__u8 * buffer, ft_format_type new_code)
  47. {
  48. static __u8 list[BAD_SECTOR_MAP_SIZE];
  49. SectorMap *src_ptr = (SectorMap *) list;
  50. __u8 *dst_ptr = bad_sector_map;
  51. SectorMap map;
  52. unsigned int sector = 1;
  53. int i;
  54. if (format_code != fmt_var && format_code != fmt_big) {
  55. memcpy(list, bad_sector_map, sizeof(list));
  56. memset(bad_sector_map, 0, sizeof(bad_sector_map));
  57. while ((__u8 *) src_ptr - list < sizeof(list)) {
  58. map = *src_ptr++;
  59. if (map == EMPTY_SEGMENT) {
  60. *(SectorMap *) dst_ptr = 0x800000 + sector;
  61. dst_ptr += 3;
  62. sector += SECTORS_PER_SEGMENT;
  63. } else {
  64. for (i = 0; i < SECTORS_PER_SEGMENT; ++i) {
  65. if (map & 1) {
  66. *(SewctorMap *) dst_ptr = sector;
  67. dst_ptr += 3;
  68. }
  69. map >>= 1;
  70. ++sector;
  71. }
  72. }
  73. }
  74. }
  75. bad_sector_map_changed = 1;
  76. *(buffer + 4) = new_code; /* put new format code */
  77. if (format_code != fmt_var && new_code == fmt_big) {
  78. PUT4(buffer, FT_6_HSEG_1, (__u32)GET2(buffer, 6));
  79. PUT4(buffer, FT_6_HSEG_2, (__u32)GET2(buffer, 8));
  80. PUT4(buffer, FT_6_FRST_SEG, (__u32)GET2(buffer, 10));
  81. PUT4(buffer, FT_6_LAST_SEG, (__u32)GET2(buffer, 12));
  82. memset(buffer+6, '\0', 8);
  83. }
  84. format_code = new_code;
  85. }
  86. #endif
  87. /* given buffer that contains a header segment, find the end of
  88. * of the bsm list
  89. */
  90. __u8 * ftape_find_end_of_bsm_list(__u8 * address)
  91. {
  92. __u8 *ptr = address + FT_HEADER_END; /* start of bsm list */
  93. __u8 *limit = address + FT_SEGMENT_SIZE;
  94. while (ptr + 2 < limit) {
  95. if (ptr[0] || ptr[1] || ptr[2]) {
  96. ptr += 3;
  97. } else {
  98. return ptr;
  99. }
  100. }
  101. return NULL;
  102. }
  103. static inline void put_sector(SectorCount *ptr, unsigned int sector)
  104. {
  105. ptr->bytes[0] = sector & 0xff;
  106. sector >>= 8;
  107. ptr->bytes[1] = sector & 0xff;
  108. sector >>= 8;
  109. ptr->bytes[2] = sector & 0xff;
  110. }
  111. static inline unsigned int get_sector(SectorCount *ptr)
  112. {
  113. #if 1
  114. unsigned int sector;
  115. sector = ptr->bytes[0];
  116. sector += ptr->bytes[1] << 8;
  117. sector += ptr->bytes[2] << 16;
  118. return sector;
  119. #else
  120. /* GET4 gets the next four bytes in Intel little endian order
  121. * and converts them to host byte order and handles unaligned
  122. * access.
  123. */
  124. return (GET4(ptr, 0) & 0x00ffffff); /* back to host byte order */
  125. #endif
  126. }
  127. static void bsm_debug_fake(void)
  128. {
  129. /* for testing of bad sector handling at end of tape
  130. */
  131. #if 0
  132. ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 3,
  133. 0x000003e0;
  134. ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 2,
  135. 0xff3fffff;
  136. ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 1,
  137. 0xffffe000;
  138. #endif
  139. /* Enable to test bad sector handling
  140. */
  141. #if 0
  142. ftape_put_bad_sector_entry(30, 0xfffffffe)
  143. ftape_put_bad_sector_entry(32, 0x7fffffff);
  144. ftape_put_bad_sector_entry(34, 0xfffeffff);
  145. ftape_put_bad_sector_entry(36, 0x55555555);
  146. ftape_put_bad_sector_entry(38, 0xffffffff);
  147. ftape_put_bad_sector_entry(50, 0xffff0000);
  148. ftape_put_bad_sector_entry(51, 0xffffffff);
  149. ftape_put_bad_sector_entry(52, 0xffffffff);
  150. ftape_put_bad_sector_entry(53, 0x0000ffff);
  151. #endif
  152. /* Enable when testing multiple volume tar dumps.
  153. */
  154. #if 0
  155. {
  156. int i;
  157. for (i = ft_first_data_segment;
  158. i <= ft_last_data_segment - 7; ++i) {
  159. ftape_put_bad_sector_entry(i, EMPTY_SEGMENT);
  160. }
  161. }
  162. #endif
  163. /* Enable when testing bit positions in *_error_map
  164. */
  165. #if 0
  166. {
  167. int i;
  168. for (i = first_data_segment; i <= last_data_segment; ++i) {
  169. ftape_put_bad_sector_entry(i,
  170. ftape_get_bad_sector_entry(i)
  171. | 0x00ff00ff);
  172. }
  173. }
  174. #endif
  175. }
  176. static void print_bad_sector_map(void)
  177. {
  178. unsigned int good_sectors;
  179. unsigned int total_bad = 0;
  180. int i;
  181. TRACE_FUN(ft_t_flow);
  182. if (ft_format_code == fmt_big ||
  183. ft_format_code == fmt_var ||
  184. ft_format_code == fmt_1100ft) {
  185. SectorCount *ptr = (SectorCount *)bad_sector_map;
  186. unsigned int sector;
  187. __u16 *ptr16;
  188. while((sector = get_sector(ptr++)) != 0) {
  189. if ((ft_format_code == fmt_big ||
  190. ft_format_code == fmt_var) &&
  191. sector & 0x800000) {
  192. total_bad += FT_SECTORS_PER_SEGMENT - 3;
  193. TRACE(ft_t_noise, "bad segment at sector: %6d",
  194. sector & 0x7fffff);
  195. } else {
  196. ++total_bad;
  197. TRACE(ft_t_noise, "bad sector: %6d", sector);
  198. }
  199. }
  200. /* Display old ftape's end-of-file marks
  201. */
  202. ptr16 = (__u16*)ptr;
  203. while ((sector = get_unaligned(ptr16++)) != 0) {
  204. TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d",
  205. sector, get_unaligned(ptr16++));
  206. }
  207. } else { /* fixed size format */
  208. for (i = ft_first_data_segment;
  209. i < (int)(ft_segments_per_track * ft_tracks_per_tape); ++i) {
  210. SectorMap map = ((SectorMap *) bad_sector_map)[i];
  211. if (map) {
  212. TRACE(ft_t_noise,
  213. "bsm for segment %4d: 0x%08x", i, (unsigned int)map);
  214. total_bad += ((map == EMPTY_SEGMENT)
  215. ? FT_SECTORS_PER_SEGMENT - 3
  216. : count_ones(map));
  217. }
  218. }
  219. }
  220. good_sectors =
  221. ((ft_segments_per_track * ft_tracks_per_tape - ft_first_data_segment)
  222. * (FT_SECTORS_PER_SEGMENT - 3)) - total_bad;
  223. TRACE(ft_t_info, "%d Kb usable on this tape", good_sectors);
  224. if (total_bad == 0) {
  225. TRACE(ft_t_info,
  226. "WARNING: this tape has no bad blocks registered !");
  227. } else {
  228. TRACE(ft_t_info, "%d bad sectors", total_bad);
  229. }
  230. TRACE_EXIT;
  231. }
  232. void ftape_extract_bad_sector_map(__u8 * buffer)
  233. {
  234. TRACE_FUN(ft_t_any);
  235. /* Fill the bad sector map with the contents of buffer.
  236. */
  237. if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
  238. /* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed
  239. * sector log but use this area to extend the bad sector map.
  240. */
  241. bad_sector_map = &buffer[FT_HEADER_END];
  242. } else {
  243. /* non-wide QIC-80 tapes have a failed sector log area that
  244. * mustn't be included in the bad sector map.
  245. */
  246. bad_sector_map = &buffer[FT_FSL + FT_FSL_SIZE];
  247. }
  248. if (ft_format_code == fmt_1100ft ||
  249. ft_format_code == fmt_var ||
  250. ft_format_code == fmt_big) {
  251. bsm_hash_ptr = (SectorCount *)bad_sector_map;
  252. } else {
  253. bsm_hash_ptr = NULL;
  254. }
  255. bsm_debug_fake();
  256. if (TRACE_LEVEL >= ft_t_info) {
  257. print_bad_sector_map();
  258. }
  259. TRACE_EXIT;
  260. }
  261. static inline SectorMap cvt2map(unsigned int sector)
  262. {
  263. return 1 << (((sector & 0x7fffff) - 1) % FT_SECTORS_PER_SEGMENT);
  264. }
  265. static inline int cvt2segment(unsigned int sector)
  266. {
  267. return ((sector & 0x7fffff) - 1) / FT_SECTORS_PER_SEGMENT;
  268. }
  269. static int forward_seek_entry(int segment_id,
  270. SectorCount **ptr,
  271. SectorMap *map)
  272. {
  273. unsigned int sector;
  274. int segment;
  275. do {
  276. sector = get_sector((*ptr)++);
  277. segment = cvt2segment(sector);
  278. } while (sector != 0 && segment < segment_id);
  279. (*ptr) --; /* point to first sector >= segment_id */
  280. /* Get all sectors in segment_id
  281. */
  282. if (sector == 0 || segment != segment_id) {
  283. *map = 0;
  284. return 0;
  285. } else if ((sector & 0x800000) &&
  286. (ft_format_code == fmt_var || ft_format_code == fmt_big)) {
  287. *map = EMPTY_SEGMENT;
  288. return FT_SECTORS_PER_SEGMENT;
  289. } else {
  290. int count = 1;
  291. SectorCount *tmp_ptr = (*ptr) + 1;
  292. *map = cvt2map(sector);
  293. while ((sector = get_sector(tmp_ptr++)) != 0 &&
  294. (segment = cvt2segment(sector)) == segment_id) {
  295. *map |= cvt2map(sector);
  296. ++count;
  297. }
  298. return count;
  299. }
  300. }
  301. static int backwards_seek_entry(int segment_id,
  302. SectorCount **ptr,
  303. SectorMap *map)
  304. {
  305. unsigned int sector;
  306. int segment; /* max unsigned int */
  307. if (*ptr <= (SectorCount *)bad_sector_map) {
  308. *map = 0;
  309. return 0;
  310. }
  311. do {
  312. sector = get_sector(--(*ptr));
  313. segment = cvt2segment(sector);
  314. } while (*ptr > (SectorCount *)bad_sector_map && segment > segment_id);
  315. if (segment > segment_id) { /* at start of list, no entry found */
  316. *map = 0;
  317. return 0;
  318. } else if (segment < segment_id) {
  319. /* before smaller entry, adjust for overshoot */
  320. (*ptr) ++;
  321. *map = 0;
  322. return 0;
  323. } else if ((sector & 0x800000) &&
  324. (ft_format_code == fmt_big || ft_format_code == fmt_var)) {
  325. *map = EMPTY_SEGMENT;
  326. return FT_SECTORS_PER_SEGMENT;
  327. } else { /* get all sectors in segment_id */
  328. int count = 1;
  329. *map = cvt2map(sector);
  330. while(*ptr > (SectorCount *)bad_sector_map) {
  331. sector = get_sector(--(*ptr));
  332. segment = cvt2segment(sector);
  333. if (segment != segment_id) {
  334. break;
  335. }
  336. *map |= cvt2map(sector);
  337. ++count;
  338. }
  339. if (segment < segment_id) {
  340. (*ptr) ++;
  341. }
  342. return count;
  343. }
  344. }
  345. #if 0
  346. static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map)
  347. {
  348. SectorCount *ptr = (SectorCount *)bad_sector_map;
  349. int count;
  350. int new_count;
  351. SectorMap map;
  352. TRACE_FUN(ft_t_any);
  353. if (ft_format_code == fmt_1100ft ||
  354. ft_format_code == fmt_var ||
  355. ft_format_code == fmt_big) {
  356. count = forward_seek_entry(segment_id, &ptr, &map);
  357. new_count = count_ones(new_map);
  358. /* If format code == 4 put empty segment instead of 32
  359. * bad sectors.
  360. */
  361. if (ft_format_code == fmt_var || ft_format_code == fmt_big) {
  362. if (new_count == FT_SECTORS_PER_SEGMENT) {
  363. new_count = 1;
  364. }
  365. if (count == FT_SECTORS_PER_SEGMENT) {
  366. count = 1;
  367. }
  368. }
  369. if (count != new_count) {
  370. /* insert (or delete if < 0) new_count - count
  371. * entries. Move trailing part of list
  372. * including terminating 0.
  373. */
  374. SectorCount *hi_ptr = ptr;
  375. do {
  376. } while (get_sector(hi_ptr++) != 0);
  377. /* Note: ptr is of type byte *, and each bad sector
  378. * consumes 3 bytes.
  379. */
  380. memmove(ptr + new_count, ptr + count,
  381. (size_t)(hi_ptr - (ptr + count))*sizeof(SectorCount));
  382. }
  383. TRACE(ft_t_noise, "putting map 0x%08x at %p, segment %d",
  384. (unsigned int)new_map, ptr, segment_id);
  385. if (new_count == 1 && new_map == EMPTY_SEGMENT) {
  386. put_sector(ptr++, (0x800001 +
  387. segment_id *
  388. FT_SECTORS_PER_SEGMENT));
  389. } else {
  390. int i = 0;
  391. while (new_map) {
  392. if (new_map & 1) {
  393. put_sector(ptr++,
  394. 1 + segment_id *
  395. FT_SECTORS_PER_SEGMENT + i);
  396. }
  397. ++i;
  398. new_map >>= 1;
  399. }
  400. }
  401. } else {
  402. ((SectorMap *) bad_sector_map)[segment_id] = new_map;
  403. }
  404. TRACE_EXIT;
  405. }
  406. #endif /* 0 */
  407. SectorMap ftape_get_bad_sector_entry(int segment_id)
  408. {
  409. if (ft_used_header_segment == -1) {
  410. /* When reading header segment we'll need a blank map.
  411. */
  412. return 0;
  413. } else if (bsm_hash_ptr != NULL) {
  414. /* Invariants:
  415. * map - mask value returned on last call.
  416. * bsm_hash_ptr - points to first sector greater or equal to
  417. * first sector in last_referenced segment.
  418. * last_referenced - segment id used in the last call,
  419. * sector and map belong to this id.
  420. * This code is designed for sequential access and retries.
  421. * For true random access it may have to be redesigned.
  422. */
  423. static int last_reference = -1;
  424. static SectorMap map;
  425. if (segment_id > last_reference) {
  426. /* Skip all sectors before segment_id
  427. */
  428. forward_seek_entry(segment_id, &bsm_hash_ptr, &map);
  429. } else if (segment_id < last_reference) {
  430. /* Skip backwards until begin of buffer or
  431. * first sector in segment_id
  432. */
  433. backwards_seek_entry(segment_id, &bsm_hash_ptr, &map);
  434. } /* segment_id == last_reference : keep map */
  435. last_reference = segment_id;
  436. return map;
  437. } else {
  438. return ((SectorMap *) bad_sector_map)[segment_id];
  439. }
  440. }
  441. /* This is simply here to prevent us from overwriting other kernel
  442. * data. Writes will result in NULL Pointer dereference.
  443. */
  444. void ftape_init_bsm(void)
  445. {
  446. bad_sector_map = NULL;
  447. bsm_hash_ptr = NULL;
  448. }