📄 zftape-ctl.c
字号:
TRACE_EXIT result;} /* Sets the new blocksize in BYTES * */static int mt_setblk(int *new_size){ TRACE_FUN(ft_t_flow); if((unsigned int)(*new_size) > ZFT_MAX_BLK_SZ) { TRACE_ABORT(-EINVAL, ft_t_info, "desired blk_sz (%d) should be <= %d bytes", *new_size, ZFT_MAX_BLK_SZ); } if ((*new_size & (FT_SECTOR_SIZE-1)) != 0) { TRACE_ABORT(-EINVAL, ft_t_info, "desired blk_sz (%d) must be a multiple of %d bytes", *new_size, FT_SECTOR_SIZE); } if (*new_size == 0) { if (zft_use_compression) { TRACE_ABORT(-EINVAL, ft_t_info, "Variable block size not yet " "supported with compression"); } *new_size = 1; } zft_blk_sz = *new_size; TRACE_EXIT 0;} static int mt_setdensity(int *arg){ TRACE_FUN(ft_t_flow); SET_TRACE_LEVEL(*arg); TRACE(TRACE_LEVEL, "tracing set to %d", TRACE_LEVEL); if ((int)TRACE_LEVEL != *arg) { TRACE_EXIT -EINVAL; } TRACE_EXIT 0;} static int mt_seek(int *new_block_pos){ int result= 0; TRACE_FUN(ft_t_any); result = seek_block(0, (__s64)*new_block_pos, &zft_pos); TRACE_EXIT result;}/* OK, this is totally different from SCSI, but the worst thing that can * happen is that there is not enough defragmentated memory that can be * allocated. Also, there is a hardwired limit of 16 dma buffers in the * stock ftape module. This shouldn't bring the system down. * * NOTE: the argument specifies the total number of dma buffers to use. * The driver needs at least 3 buffers to function at all. * */static int mt_setdrvbuffer(int *cnt){ TRACE_FUN(ft_t_flow); if (*cnt < 3) { TRACE_EXIT -EINVAL; } TRACE_CATCH(ftape_set_nr_buffers(*cnt),); TRACE_EXIT 0;}/* return the block position from start of volume */static int mt_tell(int *arg){ TRACE_FUN(ft_t_flow); *arg = zft_div_blksz(zft_pos.volume_pos, zft_find_volume(zft_pos.seg_pos)->blk_sz); TRACE_EXIT 0;}static int mt_compression(int *arg){ TRACE_FUN(ft_t_flow); /* Ok. We could also check whether compression is available at * all by trying to load the compression module. We could * also check for a block size of 1 byte which is illegal * with compression. Instead of doing it here we rely on * zftape_write() to do the proper checks. */ if ((unsigned int)*arg > 1) { TRACE_EXIT -EINVAL; } if (*arg != 0 && zft_blk_sz == 1) { /* variable block size */ TRACE_ABORT(-EINVAL, ft_t_info, "Compression not yet supported " "with variable block size"); } zft_mt_compression = *arg; if ((zft_unit & ZFT_ZIP_MODE) == 0) { zft_use_compression = zft_mt_compression; } TRACE_EXIT 0;}/* check whether write access is allowed. Write access is denied when * + zft_write_protected == 1 -- this accounts for either hard write * protection of the cartridge or for * O_RDONLY access mode of the tape device * + zft_offline == 1 -- this meany that there is either no tape * or that the MTOFFLINE ioctl has been * previously issued (`soft eject') * + ft_formatted == 0 -- this means that the cartridge is not * formatted * Then we distinuguish two cases. When zft_qic_mode is TRUE, then we try * to emulate a `traditional' (aka SCSI like) UN*X tape device. Therefore we * deny writes when * + zft_qic_mode ==1 && * (!zft_tape_at_lbot() && -- tape no at logical BOT * !(zft_tape_at_eom() || -- tape not at logical EOM (or EOD) * (zft_tape_at_eom() && * zft_old_ftape()))) -- we can't add new volume to tapes * written by old ftape because ftape * don't use the volume table * * when the drive is in true raw mode (aka /dev/rawft0) then we don't * care about LBOT and EOM conditions. This device is intended for a * user level program that wants to truly implement the QIC-80 compliance * at the logical data layout level of the cartridge, i.e. implement all * that volume table and volume directory stuff etc.< */int zft_check_write_access(zft_position *pos){ TRACE_FUN(ft_t_flow); if (zft_offline) { /* offline includes no_tape */ TRACE_ABORT(-ENXIO, ft_t_info, "tape is offline or no cartridge"); } if (!ft_formatted) { TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); } if (zft_write_protected) { TRACE_ABORT(-EACCES, ft_t_info, "cartridge write protected"); } if (zft_qic_mode) { /* check BOT condition */ if (!zft_tape_at_lbot(pos)) { /* protect cartridges written by old ftape if * not at BOT because they use the vtbl * segment for storing data */ if (zft_old_ftape) { TRACE_ABORT(-EACCES, ft_t_warn, "Cannot write to cartridges written by old ftape when not at BOT"); } /* not at BOT, but allow writes at EOD, of course */ if (!zft_tape_at_eod(pos)) { TRACE_ABORT(-EACCES, ft_t_info, "tape not at BOT and not at EOD"); } } /* fine. Now the tape is either at BOT or at EOD. */ } /* or in raw mode in which case we don't care about BOT and EOD */ TRACE_EXIT 0;}/* OPEN routine called by kernel-interface code * * NOTE: this is also called by mt_reset() with dev_minor == -1 * to fake a reopen after a reset. */int _zft_open(unsigned int dev_minor, unsigned int access_mode){ static unsigned int tape_unit; static unsigned int file_access_mode; int result; TRACE_FUN(ft_t_flow); if ((int)dev_minor == -1) { /* fake reopen */ zft_unit = tape_unit; access_mode = file_access_mode; zft_init_driver(); /* reset all static data to defaults */ } else { tape_unit = dev_minor; file_access_mode = access_mode; if ((result = ftape_enable(FTAPE_SEL(dev_minor))) < 0) { TRACE_ABORT(-ENXIO, ft_t_err, "ftape_enable failed: %d", result); } if (ft_new_tape || ft_no_tape || !ft_formatted || (FTAPE_SEL(zft_unit) != FTAPE_SEL(dev_minor)) || (zft_unit & ZFT_RAW_MODE) != (dev_minor & ZFT_RAW_MODE)) { /* reset all static data to defaults, */ zft_init_driver(); } zft_unit = dev_minor; } zft_set_flags(zft_unit); /* decode the minor bits */ if (zft_blk_sz == 1 && zft_use_compression) { ftape_disable(); /* resets ft_no_tape */ TRACE_ABORT(-ENODEV, ft_t_warn, "Variable block size not yet " "supported with compression"); } /* no need for most of the buffers when no tape or not * formatted. for the read/write operations, it is the * regardless whether there is no tape, a not-formatted tape * or the whether the driver is soft offline. * Nevertheless we allow some ioctls with non-formatted tapes, * like rewind and reset. */ if (ft_no_tape || !ft_formatted) { zft_uninit_mem(); } if (ft_no_tape) { zft_offline = 1; /* so we need not test two variables */ } if ((access_mode == O_WRONLY || access_mode == O_RDWR) && (ft_write_protected || ft_no_tape)) { ftape_disable(); /* resets ft_no_tape */ TRACE_ABORT(ft_no_tape ? -ENXIO : -EROFS, ft_t_warn, "wrong access mode %s cartridge", ft_no_tape ? "without a" : "with write protected"); } zft_write_protected = (access_mode == O_RDONLY || ft_write_protected != 0); if (zft_write_protected) { TRACE(ft_t_noise, "read only access mode: %d, " "drive write protected: %d", access_mode == O_RDONLY, ft_write_protected != 0); } if (!zft_offline) { TRACE_CATCH(zft_vmalloc_once(&zft_deblock_buf,FT_SEGMENT_SIZE), ftape_disable()); } /* zft_seg_pos should be greater than the vtbl segpos but not * if in compatibility mode and only after we read in the * header segments * * might also be a problem if the user makes a backup with a * *qft* device and rewinds it with a raw device. */ if (zft_qic_mode && !zft_old_ftape && zft_pos.seg_pos >= 0 && zft_header_read && zft_pos.seg_pos <= ft_first_data_segment) { TRACE(ft_t_noise, "you probably mixed up the zftape devices!"); zft_reset_position(&zft_pos); } TRACE_EXIT 0;}/* RELEASE routine called by kernel-interface code */int _zft_close(void){ int result = 0; TRACE_FUN(ft_t_flow); if (zft_offline) { /* call the hardware release routine. Puts the drive offline */ ftape_disable(); TRACE_EXIT 0; } if (!(ft_write_protected || zft_old_ftape)) { result = zft_flush_buffers(); TRACE(ft_t_noise, "writing file mark at current position"); if (zft_qic_mode && zft_close_volume(&zft_pos) == 0) { zft_move_past_eof(&zft_pos); } if ((zft_tape_at_lbot(&zft_pos) || !(zft_unit & FTAPE_NO_REWIND))) { if (result >= 0) { result = zft_update_header_segments(); } else { TRACE(ft_t_err, "Error: unable to update header segments"); } } } ftape_abort_operation(); if (!(zft_unit & FTAPE_NO_REWIND)) { TRACE(ft_t_noise, "rewinding tape"); if (ftape_seek_to_bot() < 0 && result >= 0) { result = -EIO; /* keep old value */ } zft_reset_position(&zft_pos); } zft_zap_read_buffers(); /* now free up memory as much as possible. We don't destroy * the deblock buffer if it containes a valid segment. */ if (zft_deblock_segment == -1) { zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); } /* high level driver status, forces creation of a new volume * when calling ftape_write again and not zft_just_before_eof */ zft_io_state = zft_idle; if (going_offline) { zft_init_driver(); zft_uninit_mem(); going_offline = 0; zft_offline = 1; } else if (zft_cmpr_lock(0 /* don't load */) == 0) { (*zft_cmpr_ops->reset)(); /* unlock it again */ } zft_memory_stats(); /* call the hardware release routine. Puts the drive offline */ ftape_disable(); TRACE_EXIT result;}/* * the wrapper function around the wrapper MTIOCTOP ioctl */static int mtioctop(struct mtop *mtop, int arg_size){ int result = 0; fun_entry *mt_fun_entry; TRACE_FUN(ft_t_flow); if (arg_size != sizeof(struct mtop) || mtop->mt_op >= NR_MT_CMDS) { TRACE_EXIT -EINVAL; } TRACE(ft_t_noise, "calling MTIOCTOP command: %s", mt_funs[mtop->mt_op].name); mt_fun_entry= &mt_funs[mtop->mt_op]; zft_resid = mtop->mt_count; if (!mt_fun_entry->offline && zft_offline) { if (ft_no_tape) { TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); } else { TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); } } if (!mt_fun_entry->not_formatted && !ft_formatted) { TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); } if (!mt_fun_entry->write_protected) { TRACE_CATCH(zft_check_write_access(&zft_pos),); } if (mt_fun_entry->need_idle_state && !(zft_offline || !ft_formatted)) { TRACE_CATCH(zft_def_idle_state(),); } if (!zft_qic_mode && !mt_fun_entry->raw_mode) { TRACE_ABORT(-EACCES, ft_t_info, "Drive needs to be in QIC-80 compatibility mode for this command"); } result = (mt_fun_entry->function)(&mtop->mt_count); if (zft_tape_at_lbot(&zft_pos)) { TRACE_CATCH(zft_update_header_segments(),); } if (result >= 0) { zft_resid = 0; } TRACE_EXIT result;}/* * standard MTIOCGET ioctl */static int mtiocget(struct mtget *mtget, int arg_size){ const zft_volinfo *volume; __s64 max_tape_pos; TRACE_FUN(ft_t_flow); if (arg_size != sizeof(struct mtget)) { TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", arg_size); } mtget->mt_type = ft_drive_type.vendor_id + 0x800000; mtget->mt_dsreg = ft_last_status.space; mtget->mt_erreg = ft_last_error.space; /* error register */ mtget->mt_resid = zft_resid; /* residuum of writes, reads and * MTIOCTOP commands */ if (!zft_offline) { /* neither no_tape nor soft offline */ mtget->mt_gstat = GMT_ONLINE(~0UL); /* should rather return the status of the cartridge * than the access mode of the file, therefor use * ft_write_protected, not zft_write_protected */ if (ft_write_protected) { mtget->mt_gstat |= GMT_WR_PROT(~0UL); } if(zft_header_read) { /* this catches non-formatted */ volume = zft_find_volume(zft_pos.seg_pos); mtget->mt_fileno = volume->count; max_tape_pos = zft_capacity - zft_blk_sz; if (zft_use_compression) { max_tape_pos -= ZFT_CMPR_OVERHEAD; } if (zft_tape_at_eod(&zft_pos)) { mtget->mt_gstat |= GMT_EOD(~0UL); } if (zft_pos.tape_pos > max_tape_pos) { mtget->mt_gstat |= GMT_EOT(~0UL); } mtget->mt_blkno = zft_div_blksz(zft_pos.volume_pos, volume->blk_sz); if (zft_just_before_eof) { mtget->mt_gstat |= GMT_EOF(~0UL); } if (zft_tape_at_lbot(&zft_pos)) { mtget->mt_gstat |= GMT_BOT(~0UL); } } else { mtget->mt_fileno = mtget->mt_blkno = -1; if (mtget->mt_dsreg & QIC_STATUS_AT_BOT) { mtget->mt_gstat |= GMT_BOT(~0UL); } } } else { if (ft_no_tape) { mtget->mt_gstat = GMT_DR_OPEN(~0UL); } else { mtget->mt_gstat = 0UL; } mtget->mt_fileno = mtget->mt_blkno = -1; } TRACE_EXIT 0;}#ifdef MTIOCRDFTSEG/* * Read a floppy tape segment. This is useful for manipulating the * volume table, and read the old header segment before re-formatting * the cartridge. */static int mtiocrdftseg(struct mtftseg * mtftseg, int arg_size){ TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCRDFTSEG"); if (zft_qic_mode) { TRACE_ABORT(-EACCES, ft_t_info, "driver needs to be in raw mode for this ioctl"); } if (arg_size != sizeof(struct mtftseg)) { TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", arg_size); } if (zft_offline) { TRACE_EXIT -ENXIO; } if (mtftseg->mt_mode != FT_RD_SINGLE && mtftseg->mt_mode != FT_RD_AHEAD) { TRACE_ABORT(-EINVAL, ft_t_info, "invalid read mode"); } if (!ft_formatted) { TRACE_EXIT -EACCES; /* -ENXIO ? */ } if (!zft_header_read) { TRACE_CATCH(zft_def_idle_state(),); } if (mtftseg->mt_segno > ft_last_data_segment) { TRACE_ABORT(-EINVAL, ft_t_info, "segment number is too large"); } mtftseg->mt_result = ftape_read_segment(mtftseg->mt_segno, zft_deblock_buf,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -