📄 zftape-ctl.c
字号:
/* * Copyright (C) 1996, 1997 Claus-Justus Heine 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: /homes/cvs/ftape-stacked/ftape/zftape/zftape-ctl.c,v $ * $Revision: 1.2.6.2 $ * $Date: 1997/11/14 18:07:33 $ * * This file contains the non-read/write zftape functions * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. */#include <linux/config.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/fcntl.h>#include <linux/zftape.h>#include <asm/uaccess.h>#include "../zftape/zftape-init.h"#include "../zftape/zftape-eof.h"#include "../zftape/zftape-ctl.h"#include "../zftape/zftape-write.h"#include "../zftape/zftape-read.h"#include "../zftape/zftape-rw.h"#include "../zftape/zftape-vtbl.h"/* Global vars. */int zft_write_protected; /* this is when cartridge rdonly or O_RDONLY */int zft_header_read;int zft_offline;unsigned int zft_unit;int zft_resid;int zft_mt_compression;/* Local vars. */static int going_offline;typedef int (mt_fun)(int *argptr);typedef int (*mt_funp)(int *argptr);typedef struct{ mt_funp function; unsigned offline : 1; /* op permitted if offline or no_tape */ unsigned write_protected : 1; /* op permitted if write-protected */ unsigned not_formatted : 1; /* op permitted if tape not formatted */ unsigned raw_mode : 1; /* op permitted if zft_mode == 0 */ unsigned need_idle_state : 1; /* need to call def_idle_state */ char *name;} fun_entry;static mt_fun mt_dummy, mt_reset, mt_fsr, mt_bsr, mt_rew, mt_offl, mt_nop, mt_weof, mt_erase, mt_ras2, mt_setblk, mt_setdensity, mt_seek, mt_tell, mt_reten, mt_eom, mt_fsf, mt_bsf, mt_fsfm, mt_bsfm, mt_setdrvbuffer, mt_compression;static fun_entry mt_funs[]={ {mt_reset , 1, 1, 1, 1, 0, "MT_RESET" }, /* 0 */ {mt_fsf , 0, 1, 0, 0, 1, "MT_FSF" }, {mt_bsf , 0, 1, 0, 0, 1, "MT_BSF" }, {mt_fsr , 0, 1, 0, 1, 1, "MT_FSR" }, {mt_bsr , 0, 1, 0, 1, 1, "MT_BSR" }, {mt_weof , 0, 0, 0, 0, 0, "MT_WEOF" }, /* 5 */ {mt_rew , 0, 1, 1, 1, 0, "MT_REW" }, {mt_offl , 0, 1, 1, 1, 0, "MT_OFFL" }, {mt_nop , 1, 1, 1, 1, 0, "MT_NOP" }, {mt_reten , 0, 1, 1, 1, 0, "MT_RETEN" }, {mt_bsfm , 0, 1, 0, 0, 1, "MT_BSFM" }, /* 10 */ {mt_fsfm , 0, 1, 0, 0, 1, "MT_FSFM" }, {mt_eom , 0, 1, 0, 0, 1, "MT_EOM" }, {mt_erase , 0, 0, 0, 1, 0, "MT_ERASE" }, {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS1" }, {mt_ras2 , 0, 0, 0, 1, 0, "MT_RAS2" }, {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS3" }, {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, {mt_setblk , 1, 1, 1, 1, 1, "MT_SETBLK"}, /* 20 */ {mt_setdensity , 1, 1, 1, 1, 0, "MT_SETDENSITY"}, {mt_seek , 0, 1, 0, 1, 1, "MT_SEEK" }, {mt_dummy , 0, 1, 0, 1, 1, "MT_TELL" }, /* wr-only ?! */ {mt_setdrvbuffer, 1, 1, 1, 1, 0, "MT_SETDRVBUFFER" }, {mt_dummy , 1, 1, 1, 1, 0, "MT_FSS" }, /* 25 */ {mt_dummy , 1, 1, 1, 1, 0, "MT_BSS" }, {mt_dummy , 1, 1, 1, 1, 0, "MT_WSM" }, {mt_dummy , 1, 1, 1, 1, 0, "MT_LOCK" }, {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOCK"}, {mt_dummy , 1, 1, 1, 1, 0, "MT_LOAD" }, /* 30 */ {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOAD"}, {mt_compression , 1, 1, 1, 0, 1, "MT_COMPRESSION"}, {mt_dummy , 1, 1, 1, 1, 0, "MT_SETPART"}, {mt_dummy , 1, 1, 1, 1, 0, "MT_MKPART"}}; #define NR_MT_CMDS NR_ITEMS(mt_funs)void zft_reset_position(zft_position *pos){ TRACE_FUN(ft_t_flow); pos->seg_byte_pos = pos->volume_pos = 0; if (zft_header_read) { /* need to keep track of the volume table and * compression map. We therefor simply * position at the beginning of the first * volume. This covers old ftape archives as * well has various flavours of the * compression map segments. The worst case is * that the compression map shows up as a * additional volume in front of all others. */ pos->seg_pos = zft_find_volume(0)->start_seg; pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); } else { pos->tape_pos = 0; pos->seg_pos = -1; } zft_just_before_eof = 0; zft_deblock_segment = -1; zft_io_state = zft_idle; zft_zap_read_buffers(); zft_prevent_flush(); /* unlock the compresison module if it is loaded. * The zero arg means not to try to load the module. */ if (zft_cmpr_lock(0) == 0) { (*zft_cmpr_ops->reset)(); /* unlock */ } TRACE_EXIT;}static void zft_init_driver(void){ TRACE_FUN(ft_t_flow); zft_resid = zft_header_read = zft_old_ftape = zft_offline = zft_write_protected = going_offline = zft_mt_compression = zft_header_changed = zft_volume_table_changed = zft_written_segments = 0; zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; zft_reset_position(&zft_pos); /* does most of the stuff */ ftape_zap_read_buffers(); ftape_set_state(idle); TRACE_EXIT;}int zft_def_idle_state(void){ int result = 0; TRACE_FUN(ft_t_flow); if (!zft_header_read) { result = zft_read_header_segments(); } else if ((result = zft_flush_buffers()) >= 0 && zft_qic_mode) { /* don't move past eof */ (void)zft_close_volume(&zft_pos); } if (ftape_abort_operation() < 0) { TRACE(ft_t_warn, "ftape_abort_operation() failed"); result = -EIO; } /* clear remaining read buffers */ zft_zap_read_buffers(); zft_io_state = zft_idle; TRACE_EXIT result;}/***************************************************************************** * * * functions for the MTIOCTOP commands * * * *****************************************************************************/static int mt_dummy(int *dummy){ TRACE_FUN(ft_t_flow); TRACE_EXIT -ENOSYS;}static int mt_reset(int *dummy){ TRACE_FUN(ft_t_flow); (void)ftape_seek_to_bot(); TRACE_CATCH(ftape_reset_drive(), zft_init_driver(); zft_uninit_mem(); zft_offline = 1); /* fake a re-open of the device. This will set all flage and * allocate buffers as appropriate. The new tape condition will * force the open routine to do anything we need. */ TRACE_CATCH(_zft_open(-1 /* fake reopen */, 0 /* dummy */),); TRACE_EXIT 0;}static int mt_fsf(int *arg){ int result; TRACE_FUN(ft_t_flow); result = zft_skip_volumes(*arg, &zft_pos); zft_just_before_eof = 0; TRACE_EXIT result;}static int mt_bsf(int *arg){ int result = 0; TRACE_FUN(ft_t_flow); if (*arg != 0) { result = zft_skip_volumes(-*arg + 1, &zft_pos); } TRACE_EXIT result;}static int seek_block(__s64 data_offset, __s64 block_increment, zft_position *pos){ int result = 0; __s64 new_block_pos; __s64 vol_block_count; const zft_volinfo *volume; int exceed; TRACE_FUN(ft_t_flow); volume = zft_find_volume(pos->seg_pos); if (volume->start_seg == 0 || volume->end_seg == 0) { TRACE_EXIT -EIO; } new_block_pos = (zft_div_blksz(data_offset, volume->blk_sz) + block_increment); vol_block_count = zft_div_blksz(volume->size, volume->blk_sz); if (new_block_pos < 0) { TRACE(ft_t_noise, "new_block_pos " LL_X " < 0", LL(new_block_pos)); zft_resid = (int)new_block_pos; new_block_pos = 0; exceed = 1; } else if (new_block_pos > vol_block_count) { TRACE(ft_t_noise, "new_block_pos " LL_X " exceeds size of volume " LL_X, LL(new_block_pos), LL(vol_block_count)); zft_resid = (int)(vol_block_count - new_block_pos); new_block_pos = vol_block_count; exceed = 1; } else { exceed = 0; } if (zft_use_compression && volume->use_compression) { TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); result = (*zft_cmpr_ops->seek)(new_block_pos, pos, volume, zft_deblock_buf); pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); pos->tape_pos += pos->seg_byte_pos; } else { pos->volume_pos = zft_mul_blksz(new_block_pos, volume->blk_sz); pos->tape_pos = zft_calc_tape_pos(volume->start_seg); pos->tape_pos += pos->volume_pos; pos->seg_pos = zft_calc_seg_byte_coord(&pos->seg_byte_pos, pos->tape_pos); } zft_just_before_eof = volume->size == pos->volume_pos; if (zft_just_before_eof) { /* why this? because zft_file_no checks agains start * and end segment of a volume. We do not want to * advance to the next volume with this function. */ TRACE(ft_t_noise, "set zft_just_before_eof"); zft_position_before_eof(pos, volume); } TRACE(ft_t_noise, "\n" KERN_INFO "new_seg_pos : %d\n" KERN_INFO "new_tape_pos: " LL_X "\n" KERN_INFO "vol_size : " LL_X "\n" KERN_INFO "seg_byte_pos: %d\n" KERN_INFO "blk_sz : %d", pos->seg_pos, LL(pos->tape_pos), LL(volume->size), pos->seg_byte_pos, volume->blk_sz); if (!exceed) { zft_resid = new_block_pos - zft_div_blksz(pos->volume_pos, volume->blk_sz); } if (zft_resid < 0) { zft_resid = -zft_resid; } TRACE_EXIT ((exceed || zft_resid != 0) && result >= 0) ? -EINVAL : result;} static int mt_fsr(int *arg){ int result; TRACE_FUN(ft_t_flow); result = seek_block(zft_pos.volume_pos, *arg, &zft_pos); TRACE_EXIT result;}static int mt_bsr(int *arg){ int result; TRACE_FUN(ft_t_flow); result = seek_block(zft_pos.volume_pos, -*arg, &zft_pos); TRACE_EXIT result;}static int mt_weof(int *arg){ int result; TRACE_FUN(ft_t_flow); TRACE_CATCH(zft_flush_buffers(),); result = zft_weof(*arg, &zft_pos); TRACE_EXIT result;}static int mt_rew(int *dummy){ int result; TRACE_FUN(ft_t_flow); if(zft_header_read) { (void)zft_def_idle_state(); } result = ftape_seek_to_bot(); zft_reset_position(&zft_pos); TRACE_EXIT result;}static int mt_offl(int *dummy){ int result; TRACE_FUN(ft_t_flow); going_offline= 1; result = mt_rew(NULL); TRACE_EXIT result;}static int mt_nop(int *dummy){ TRACE_FUN(ft_t_flow); /* should we set tape status? */ if (!zft_offline) { /* offline includes no_tape */ (void)zft_def_idle_state(); } TRACE_EXIT 0; }static int mt_reten(int *dummy){ int result; TRACE_FUN(ft_t_flow); if(zft_header_read) { (void)zft_def_idle_state(); } result = ftape_seek_to_eot(); if (result >= 0) { result = ftape_seek_to_bot(); } TRACE_EXIT(result);}static int fsfbsfm(int arg, zft_position *pos){ const zft_volinfo *vtbl; __s64 block_pos; TRACE_FUN(ft_t_flow); /* What to do? This should seek to the next file-mark and * position BEFORE. That is, a next write would just extend * the current file. Well. Let's just seek to the end of the * current file, if count == 1. If count > 1, then do a * "mt_fsf(count - 1)", and then seek to the end of that file. * If count == 0, do nothing */ if (arg == 0) { TRACE_EXIT 0; } zft_just_before_eof = 0; TRACE_CATCH(zft_skip_volumes(arg < 0 ? arg : arg-1, pos), if (arg > 0) { zft_resid ++; }); vtbl = zft_find_volume(pos->seg_pos); block_pos = zft_div_blksz(vtbl->size, vtbl->blk_sz); (void)seek_block(0, block_pos, pos); if (pos->volume_pos != vtbl->size) { zft_just_before_eof = 0; zft_resid = 1; /* we didn't managed to go there */ TRACE_ABORT(-EIO, ft_t_err, "wanted file position " LL_X ", arrived at " LL_X, LL(vtbl->size), LL(pos->volume_pos)); } zft_just_before_eof = 1; TRACE_EXIT 0; }static int mt_bsfm(int *arg){ int result; TRACE_FUN(ft_t_flow); result = fsfbsfm(-*arg, &zft_pos); TRACE_EXIT result;}static int mt_fsfm(int *arg){ int result; TRACE_FUN(ft_t_flow); result = fsfbsfm(*arg, &zft_pos); TRACE_EXIT result;}static int mt_eom(int *dummy){ TRACE_FUN(ft_t_flow); zft_skip_to_eom(&zft_pos); TRACE_EXIT 0;}static int mt_erase(int *dummy){ int result; TRACE_FUN(ft_t_flow); result = zft_erase(); TRACE_EXIT result;}static int mt_ras2(int *dummy){ int result; TRACE_FUN(ft_t_flow); result = -ENOSYS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -