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

嵌入式Linux

开发平台:

Unix_Linux

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