📄 tapechar.c
字号:
/*************************************************************************** * * drivers/s390/char/tapechar.c * character device frontend for tape device driver * * S390 and zSeries version * Copyright (C) 2001 IBM Corporation * Author(s): Carsten Otte <cotte@de.ibm.com> * Tuan Ngo-Anh <ngoanh@de.ibm.com> * * **************************************************************************** */#include "tapedefs.h"#include <linux/config.h>#include <linux/version.h>#include <linux/types.h>#include <linux/proc_fs.h>#include <asm/ccwcache.h> /* CCW allocations */#include <asm/s390dyn.h>#include <asm/debug.h>#include <linux/mtio.h>#include <asm/uaccess.h>#include <linux/compatmac.h>#ifdef MODULE#define __NO_VERSION__#include <linux/module.h>#endif#include "tape.h"#include "tapechar.h"#define PRINTK_HEADER "TCHAR:"/* * file operation structure for tape devices */static struct file_operations tape_fops ={ // owner : THIS_MODULE, llseek:NULL, /* lseek - default */ read:tape_read, /* read */ write:tape_write, /* write */ readdir:NULL, /* readdir - bad */ poll:NULL, /* poll */ ioctl:tape_ioctl, /* ioctl */ mmap:NULL, /* mmap */ open:tape_open, /* open */ flush:NULL, /* flush */ release:tape_release, /* release */ fsync:NULL, /* fsync */ fasync:NULL, /* fasync */ lock:NULL,};int tape_major = TAPE_MAJOR;#ifdef CONFIG_DEVFS_FSvoidtapechar_mkdevfstree (tape_info_t* ti) { ti->devfs_char_dir=devfs_mk_dir (ti->devfs_dir, "char", ti); ti->devfs_nonrewinding=devfs_register(ti->devfs_char_dir, "nonrewinding", DEVFS_FL_DEFAULT,tape_major, ti->nor_minor, TAPECHAR_DEFAULTMODE, &tape_fops, ti); ti->devfs_rewinding=devfs_register(ti->devfs_char_dir, "rewinding", DEVFS_FL_DEFAULT, tape_major, ti->rew_minor, TAPECHAR_DEFAULTMODE, &tape_fops, ti);}voidtapechar_rmdevfstree (tape_info_t* ti) { devfs_unregister(ti->devfs_nonrewinding); devfs_unregister(ti->devfs_rewinding); devfs_unregister(ti->devfs_char_dir);}#endifvoidtapechar_setup (tape_info_t * ti){#ifdef CONFIG_DEVFS_FS tapechar_mkdevfstree(ti);#endif}voidtapechar_init (void){ int result; tape_frontend_t *charfront,*temp; tape_info_t* ti; tape_init(); /* Register the tape major number to the kernel */#ifdef CONFIG_DEVFS_FS result = devfs_register_chrdev (tape_major, "tape", &tape_fops);#else result = register_chrdev (tape_major, "tape", &tape_fops);#endif if (result < 0) { PRINT_WARN (KERN_ERR "tape: can't get major %d\n", tape_major);#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"c:initfail"); debug_text_event (tape_debug_area,3,"regchrfail");#endif /* TAPE_DEBUG */ panic ("no major number available for tape char device"); } if (tape_major == 0) tape_major = result; /* accept dynamic major number */ PRINT_WARN (KERN_ERR " tape gets major %d for character device\n", result); charfront = kmalloc (sizeof (tape_frontend_t), GFP_KERNEL); if (charfront == NULL) {#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"c:initfail"); debug_text_event (tape_debug_area,3,"no mem");#endif /* TAPE_DEBUG */ panic ("no major number available for tape char device"); } charfront->device_setup = tapechar_setup;#ifdef CONFIG_DEVFS_FS charfront->mkdevfstree = tapechar_mkdevfstree; charfront->rmdevfstree = tapechar_rmdevfstree;#endif#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"c:init ok");#endif /* TAPE_DEBUG */ charfront->next=NULL; if (first_frontend==NULL) { first_frontend=charfront; } else { temp=first_frontend; while (temp->next!=NULL) temp=temp->next; temp->next=charfront; } ti=first_tape_info; while (ti!=NULL) { tapechar_setup(ti); ti=ti->next; }}voidtapechar_uninit (void){ unregister_chrdev (tape_major, "tape");}/* * Tape device read function */ssize_ttape_read (struct file *filp, char *data, size_t count, loff_t * ppos){ long lockflags; tape_info_t *ti; size_t block_size; ccw_req_t *cqr; int rc;#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:read");#endif /* TAPE_DEBUG */ ti = first_tape_info; while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp)) ti = (tape_info_t *) ti->next; if (ti == NULL) {#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:nodev");#endif /* TAPE_DEBUG */ return -ENODEV; } if (ppos != &filp->f_pos) { /* "A request was outside the capabilities of the device." */#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:ppos wrong");#endif /* TAPE_DEBUG */ return -EOVERFLOW; /* errno=75 Value too large for def. data type */ } if (ti->block_size == 0) { block_size = count; } else { block_size = ti->block_size; }#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:nbytes:"); debug_int_event (tape_debug_area,6,block_size);#endif cqr = ti->discipline->read_block (data, block_size, ti); if (!cqr) { return -ENOBUFS; } s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); ti->cqr = cqr; ti->wanna_wakeup=0; rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options); if (rc) { tapestate_set(ti,TS_IDLE); kfree (cqr); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); return rc; } s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); wait_event (ti->wq,ti->wanna_wakeup); ti->cqr = NULL; ti->discipline->free_read_block (cqr, ti); s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); if (tapestate_get (ti) == TS_FAILED) { tapestate_set (ti, TS_IDLE); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); return ti->rc; } if (tapestate_get (ti) == TS_NOT_OPER) { ti->blk_minor=ti->rew_minor=ti->nor_minor=-1; ti->devinfo.irq=-1; s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags); return -ENODEV; } if (tapestate_get (ti) != TS_DONE) { tapestate_set (ti, TS_IDLE); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); return -EIO; } tapestate_set (ti, TS_IDLE); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:rbytes:"); debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);#endif /* TAPE_DEBUG */ filp->f_pos += block_size - ti->devstat.rescnt; return block_size - ti->devstat.rescnt;}/* * Tape device write function */ssize_ttape_write (struct file *filp, const char *data, size_t count, loff_t * ppos){ long lockflags; tape_info_t *ti; size_t block_size; ccw_req_t *cqr; int nblocks, i, rc; size_t written = 0;#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:write");#endif ti = first_tape_info; while ((ti != NULL) && (ti->nor_filp != filp) && (ti->rew_filp != filp)) ti = (tape_info_t *) ti->next; if (ti == NULL) return -ENODEV; if (ppos != &filp->f_pos) { /* "A request was outside the capabilities of the device." */#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:ppos wrong");#endif return -EOVERFLOW; /* errno=75 Value too large for def. data type */ } if ((ti->block_size != 0) && (count % ti->block_size != 0)) return -EIO; if (ti->block_size == 0) { block_size = count; nblocks = 1; } else { block_size = ti->block_size; nblocks = count / (ti->block_size); }#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:nbytes:"); debug_int_event (tape_debug_area,6,block_size); debug_text_event (tape_debug_area,6,"c:nblocks:"); debug_int_event (tape_debug_area,6,nblocks);#endif for (i = 0; i < nblocks; i++) { cqr = ti->discipline->write_block (data + i * block_size, block_size, ti); if (!cqr) { return -ENOBUFS; } s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); ti->cqr = cqr; ti->wanna_wakeup=0; rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); wait_event_interruptible (ti->wq,ti->wanna_wakeup); ti->cqr = NULL; ti->discipline->free_write_block (cqr, ti); if (signal_pending (current)) { tapestate_set (ti, TS_IDLE); return -ERESTARTSYS; } s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); if (tapestate_get (ti) == TS_FAILED) { tapestate_set (ti, TS_IDLE); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); if ((ti->rc==-ENOSPC) && (i!=0)) return i*block_size; return ti->rc; } if (tapestate_get (ti) == TS_NOT_OPER) { ti->blk_minor=ti->rew_minor=ti->nor_minor=-1; ti->devinfo.irq=-1; s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags); return -ENODEV; } if (tapestate_get (ti) != TS_DONE) { tapestate_set (ti, TS_IDLE); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); return -EIO; } tapestate_set (ti, TS_IDLE); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:wbytes:"); debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);#endif filp->f_pos += block_size - ti->devstat.rescnt; written += block_size - ti->devstat.rescnt; if (ti->devstat.rescnt > 0) return written; }#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:wtotal:"); debug_int_event (tape_debug_area,6,written);#endif return written;}static inttape_mtioctop (struct file *filp, short mt_op, int mt_count){ tape_info_t *ti; ccw_req_t *cqr = NULL; int rc; long lockflags;#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:mtio"); debug_text_event (tape_debug_area,6,"c:ioop:"); debug_int_event (tape_debug_area,6,mt_op); debug_text_event (tape_debug_area,6,"c:arg:"); debug_int_event (tape_debug_area,6,mt_count);#endif ti = first_tape_info; while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp)) ti = (tape_info_t *) ti->next; if (ti == NULL) return -ENODEV; switch (mt_op) { case MTREW: // rewind cqr = ti->discipline->mtrew (ti, mt_count); break; case MTOFFL: // put drive offline cqr = ti->discipline->mtoffl (ti, mt_count); break; case MTUNLOAD: // unload the tape cqr = ti->discipline->mtunload (ti, mt_count); break; case MTWEOF: // write tapemark cqr = ti->discipline->mtweof (ti, mt_count); break; case MTFSF: // forward space file cqr = ti->discipline->mtfsf (ti, mt_count); break; case MTBSF: // backward space file cqr = ti->discipline->mtbsf (ti, mt_count); break; case MTFSFM: // forward space file, stop at BOT side cqr = ti->discipline->mtfsfm (ti, mt_count); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -