⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftape-bsm.c

📁 arm平台上的uclinux系统全部源代码
💻 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 + -