📄 ftape-bsm.c
字号:
/* * Copyright (C) 1994-1995 Bas Laarhoven. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $Source: /usr/local/cvsroot/AplioTRIO/linux/drivers/char/ftape/ftape-bsm.c,v $ $Author: vadim $ * $Revision: 1.1.1.1 $ $Date: 1999/11/15 13:41:57 $ $State: Exp $ * * This file contains the bad-sector map handling code for * the QIC-117 floppy tape driver for Linux. * QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented. */#include <linux/ftape.h>#include <linux/string.h>#include "tracing.h"#include "ftape-bsm.h"#include "ftape-ctl.h"#include "ftape-rw.h"/* Global vars. */int bad_sector_map_changed = 0;/* Local vars. */static byte bad_sector_map[BAD_SECTOR_MAP_SIZE];typedef enum { forward, backward} mode_type;#if 0/* fix_tape converts a normal QIC-80 tape into a 'wide' tape. * For testing purposes only ! */void fix_tape(byte * buffer){ static byte list[BAD_SECTOR_MAP_SIZE]; unsigned long *src_ptr = (unsigned long *) list; byte *dst_ptr = bad_sector_map; unsigned long map; unsigned sector = 1; int i; memcpy(list, bad_sector_map, sizeof(list)); memset(bad_sector_map, 0, sizeof(bad_sector_map)); while ((byte *) src_ptr - list < sizeof(list)) { map = *src_ptr++; if (map == EMPTY_SEGMENT) { *(unsigned long *) dst_ptr = 0x800000 + sector; dst_ptr += 3; sector += SECTORS_PER_SEGMENT; } else { for (i = 0; i < SECTORS_PER_SEGMENT; ++i) { if (map & 1) { *(unsigned long *) dst_ptr = sector; dst_ptr += 3; } map >>= 1; ++sector; } } } bad_sector_map_changed = 1; *(buffer + 4) = 4; /* put new format code */ format_code = 4;}#endifbyte * find_end_of_bsm_list(byte * ptr, byte * limit){ while (ptr + 2 < limit) { if (ptr[0] || ptr[1] || ptr[2]) { ptr += 3; } else { return ptr; } } return NULL;}void store_bad_sector_map(byte * buffer){ TRACE_FUN(8, "store_bad_sector_map"); size_t count; size_t offset; /* Store the bad sector map in buffer. */ if (format_code == 4) { offset = 256; count = sizeof(bad_sector_map); } else { offset = 2 * SECTOR_SIZE; /* skip failed sector log */ count = sizeof(bad_sector_map) - (offset - 256); } memcpy(buffer + offset, bad_sector_map, count); TRACE_EXIT;}void put_sector(byte ** ptr, unsigned long sector){ *(*ptr)++ = sector & 0xff; sector >>= 8; *(*ptr)++ = sector & 0xff; sector >>= 8; *(*ptr)++ = sector & 0xff;}unsigned long get_sector(byte ** ptr, mode_type mode){ unsigned long sector; if (mode == forward) { sector = *(*ptr)++; sector += *(*ptr)++ << 8; sector += *(*ptr)++ << 16; } else { sector = *--(*ptr) << 16; sector += *--(*ptr) << 8; sector += *--(*ptr); } return sector;}void extract_bad_sector_map(byte * buffer){ TRACE_FUN(8, "extract_bad_sector_map"); /* Fill the bad sector map with the contents of buffer. */ if (format_code == 4) { /* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed * sector log but use this area to extend the bad sector map. */ memcpy(bad_sector_map, buffer + 256, sizeof(bad_sector_map)); } else { /* non-wide QIC-80 tapes have a failed sector log area that * mustn't be included in the bad sector map. */ memcpy(bad_sector_map, buffer + 256 + FAILED_SECTOR_LOG_SIZE, sizeof(bad_sector_map) - FAILED_SECTOR_LOG_SIZE); }#if 0 /* for testing of bad sector handling at end of tape */ ((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 3] = 0x000003e0; ((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 2] = 0xff3fffff; ((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 1] = 0xffffe000;#endif#if 0 /* Enable to test bad sector handling */ ((unsigned long *) bad_sector_map)[30] = 0xfffffffe; ((unsigned long *) bad_sector_map)[32] = 0x7fffffff; ((unsigned long *) bad_sector_map)[34] = 0xfffeffff; ((unsigned long *) bad_sector_map)[36] = 0x55555555; ((unsigned long *) bad_sector_map)[38] = 0xffffffff; ((unsigned long *) bad_sector_map)[50] = 0xffff0000; ((unsigned long *) bad_sector_map)[51] = 0xffffffff; ((unsigned long *) bad_sector_map)[52] = 0xffffffff; ((unsigned long *) bad_sector_map)[53] = 0x0000ffff;#endif#if 0 /* Enable when testing multiple volume tar dumps. */ for (i = first_data_segment; i <= ftape_last_segment.id - 7; ++i) { ((unsigned long *) bad_sector_map)[i] = EMPTY_SEGMENT; }#endif#if 0 /* Enable when testing bit positions in *_error_map */ for (i = first_data_segment; i <= ftape_last_segment.id; ++i) { ((unsigned long *) bad_sector_map)[i] |= 0x00ff00ff; }#endif if (tracing > 2) { unsigned int map; int good_sectors = 0; int bad_sectors; unsigned int total_bad = 0; int i; if (format_code == 4 || format_code == 3) { byte *ptr = bad_sector_map; unsigned sector; do { sector = get_sector(&ptr, forward); if (sector != 0) { if (format_code == 4 && sector & 0x800000) { total_bad += SECTORS_PER_SEGMENT - 3; TRACEx1(6, "bad segment at sector: %6d", sector & 0x7fffff); } else { ++total_bad; TRACEx1(6, "bad sector: %6d", sector); } } } while (sector != 0); /* Display end-of-file marks */ do { sector = *((unsigned short *) ptr)++; if (sector) { TRACEx2(4, "eof mark: %4d/%2d", sector, *((unsigned short *) ptr)++); } } while (sector); } else { for (i = first_data_segment; i < segments_per_track * tracks_per_tape; ++i) { map = ((unsigned long *) bad_sector_map)[i]; bad_sectors = count_ones(map); if (bad_sectors > 0) { TRACEx2(6, "bsm for segment %4d: 0x%08x", i, map); if (bad_sectors > SECTORS_PER_SEGMENT - 3) { bad_sectors = SECTORS_PER_SEGMENT - 3; } total_bad += bad_sectors; } } } good_sectors = ((segments_per_track * tracks_per_tape - first_data_segment) * (SECTORS_PER_SEGMENT - 3)) - total_bad; TRACEx1(3, "%d Kb usable on this tape", good_sectors - ftape_last_segment.free); if (total_bad == 0) { TRACE(1, "WARNING: this tape has no bad blocks registered !"); } else { TRACEx1(2, "%d bad sectors", total_bad); } } TRACE_EXIT;}unsigned long cvt2map(int sector){ return 1 << (((sector & 0x7fffff) - 1) % SECTORS_PER_SEGMENT);}int cvt2segment(int sector){ return ((sector & 0x7fffff) - 1) / SECTORS_PER_SEGMENT;}int forward_seek_entry(int segment_id, byte ** ptr, unsigned long *map){ byte *tmp_ptr; unsigned long sector; int segment; int count; do { sector = get_sector(ptr, forward); segment = cvt2segment(sector); } while (sector != 0 && segment < segment_id); tmp_ptr = *ptr - 3; /* point to first sector >= segment_id */ /* Get all sectors in segment_id */ if (format_code == 4 && (sector & 0x800000) && segment == segment_id) { *map = EMPTY_SEGMENT; count = 32; } else { *map = 0; count = 0; while (sector != 0 && segment == segment_id) { *map |= cvt2map(sector); sector = get_sector(ptr, forward); segment = cvt2segment(sector); ++count; } } *ptr = tmp_ptr; return count;}int backwards_seek_entry(int segment_id, byte ** ptr, unsigned long *map){ unsigned long sector; int segment; int count; *map = 0; if (*ptr > bad_sector_map) { do { sector = get_sector(ptr, backward); segment = cvt2segment(sector); } while (*ptr > bad_sector_map && segment > segment_id); count = 0; if (segment > segment_id) { /* at start of list, no entry found */ } else if (segment < segment_id) { /* before smaller entry, adjust for overshoot */ *ptr += 3; } else { /* get all sectors in segment_id */ if (format_code == 4 && (sector & 0x800000)) { *map = EMPTY_SEGMENT; count = 32; } else { do { *map |= cvt2map(sector); ++count; if (*ptr <= bad_sector_map) { break; } sector = get_sector(ptr, backward); segment = cvt2segment(sector); } while (segment == segment_id); if (segment < segment_id) { *ptr += 3; } } } } else { count = 0; } return count;}void put_bad_sector_entry(int segment_id, unsigned long new_map){ byte *ptr = bad_sector_map; int count; int new_count; unsigned long map; if (format_code == 3 || format_code == 4) { count = forward_seek_entry(segment_id, &ptr, &map); new_count = count_ones(new_map); /* If format code == 4 put empty segment instead of 32 bad sectors. */ if (new_count == 32 && format_code == 4) { new_count = 1; } if (count != new_count) { /* insert (or delete if < 0) new_count - count entries. * Move trailing part of list including terminating 0. */ byte *hi_ptr = ptr; do { } while (get_sector(&hi_ptr, forward) != 0); memmove(ptr + new_count, ptr + count, hi_ptr - (ptr + count)); } if (new_count == 1 && new_map == EMPTY_SEGMENT) { put_sector(&ptr, 0x800001 + segment_id * SECTORS_PER_SEGMENT); } else { int i = 0; while (new_map) { if (new_map & 1) { put_sector(&ptr, 1 + segment_id * SECTORS_PER_SEGMENT + i); } ++i; new_map >>= 1; } } } else { ((unsigned long *) bad_sector_map)[segment_id] = new_map; } bad_sector_map_changed = 1;}unsigned long get_bad_sector_entry(int segment_id){ TRACE_FUN(8, "get_bad_sector_entry"); static unsigned long map = 0; if (used_header_segment == -1) { /* When reading header segment we'll need a blank map. */ map = 0; } else if (format_code == 3 || format_code == 4) { /* Invariants: * map - mask value returned on last call. * ptr - points to first sector greater or equal to * first sector in last_referenced segment. * last_referenced - segment id used in the last call, * sector and map belong to this id. * This code is designed for sequential access and retries. * For true random access it may have to be redesigned. */ static int last_reference = -1; static byte *ptr = bad_sector_map; if (segment_id > last_reference) { /* Skip all sectors before segment_id */ forward_seek_entry(segment_id, &ptr, &map); } else if (segment_id < last_reference) { /* Skip backwards until begin of buffer or first sector in segment_id */ backwards_seek_entry(segment_id, &ptr, &map); } /* segment_id == last_reference : keep map */ last_reference = segment_id; } else { map = ((unsigned long *) bad_sector_map)[segment_id]; } TRACE_EXIT; return map;}void ftape_init_bsm(void){ memset(bad_sector_map, 0, sizeof(bad_sector_map));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -