tapechar.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:21k
- /***************************************************************************
- *
- * 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_FS
- void
- tapechar_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);
- }
- void
- tapechar_rmdevfstree (tape_info_t* ti) {
- devfs_unregister(ti->devfs_nonrewinding);
- devfs_unregister(ti->devfs_rewinding);
- devfs_unregister(ti->devfs_char_dir);
- }
- #endif
- void
- tapechar_setup (tape_info_t * ti)
- {
- #ifdef CONFIG_DEVFS_FS
- tapechar_mkdevfstree(ti);
- #endif
- }
- void
- tapechar_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 %dn", 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 devicen", 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;
- }
- }
- void
- tapechar_uninit (void)
- {
- unregister_chrdev (tape_major, "tape");
- }
- /*
- * Tape device read function
- */
- ssize_t
- tape_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_t
- tape_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 int
- tape_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;
- case MTBSFM: // backward space file, stop at BOT side
- cqr = ti->discipline->mtbsfm (ti, mt_count);
- break;
- case MTFSR: // forward space file
- cqr = ti->discipline->mtfsr (ti, mt_count);
- break;
- case MTBSR: // backward space file
- cqr = ti->discipline->mtbsr (ti, mt_count);
- break;
- case MTNOP:
- cqr = ti->discipline->mtnop (ti, mt_count);
- break;
- case MTEOM: // postion at the end of portion
- case MTRETEN: // retension the tape
- cqr = ti->discipline->mteom (ti, mt_count);
- break;
- case MTERASE:
- cqr = ti->discipline->mterase (ti, mt_count);
- break;
- case MTSETDENSITY:
- cqr = ti->discipline->mtsetdensity (ti, mt_count);
- break;
- case MTSEEK:
- cqr = ti->discipline->mtseek (ti, mt_count);
- break;
- case MTSETDRVBUFFER:
- cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
- break;
- case MTLOCK:
- cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
- break;
- case MTUNLOCK:
- cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
- break;
- case MTLOAD:
- cqr = ti->discipline->mtload (ti, mt_count);
- if (cqr!=NULL) break; // if backend driver has an load function ->use it
- // if no medium is in, wait until it gets inserted
- if (ti->medium_is_unloaded) {
- wait_event_interruptible (ti->wq,ti->medium_is_unloaded==0);
- }
- return 0;
- case MTCOMPRESSION:
- cqr = ti->discipline->mtcompression (ti, mt_count);
- break;
- case MTSETPART:
- cqr = ti->discipline->mtsetpart (ti, mt_count);
- break;
- case MTMKPART:
- cqr = ti->discipline->mtmkpart (ti, mt_count);
- break;
- case MTTELL: // return number of block relative to current file
- cqr = ti->discipline->mttell (ti, mt_count);
- break;
- case MTSETBLK:
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- ti->block_size = mt_count;
- s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:setblk:");
- debug_int_event (tape_debug_area,6,mt_count);
- #endif
- return 0;
- case MTRESET:
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- ti->kernbuf = ti->userbuf = NULL;
- tapestate_set (ti, TS_IDLE);
- ti->block_size = 0;
- s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:devreset:");
- debug_int_event (tape_debug_area,6,ti->blk_minor);
- #endif
- return 0;
- default:
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:inv.mtio");
- #endif
- return -EINVAL;
- }
- if (cqr == NULL) {
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:ccwg fail");
- #endif
- return -ENOSPC;
- }
- 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;
- if (ti->kernbuf != NULL) {
- kfree (ti->kernbuf);
- ti->kernbuf = NULL;
- }
- tape_free_request (cqr);
- // if medium was unloaded, update the corresponding variable.
- switch (mt_op) {
- case MTOFFL:
- case MTUNLOAD:
- ti->medium_is_unloaded=1;
- }
- if (signal_pending (current)) {
- tapestate_set (ti, TS_IDLE);
- return -ERESTARTSYS;
- }
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- if (((mt_op == MTEOM) || (mt_op == MTRETEN)) && (tapestate_get (ti) == TS_FAILED))
- tapestate_set (ti, TS_DONE);
- 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);
- switch (mt_op) {
- case MTRETEN: //need to rewind the tape after moving to eom
- return tape_mtioctop (filp, MTREW, 1);
- case MTFSFM: //need to skip back over the filemark
- return tape_mtioctop (filp, MTBSFM, 1);
- case MTBSF: //need to skip forward over the filemark
- return tape_mtioctop (filp, MTFSF, 1);
- }
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:mtio done");
- #endif
- return 0;
- }
- /*
- * Tape device io controls.
- */
- int
- tape_ioctl (struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
- {
- long lockflags;
- tape_info_t *ti;
- ccw_req_t *cqr;
- struct mtop op; /* structure for MTIOCTOP */
- struct mtpos pos; /* structure for MTIOCPOS */
- struct mtget get;
- int rc;
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:ioct");
- #endif
- ti = first_tape_info;
- while ((ti != NULL) &&
- (ti->rew_minor != MINOR (inode->i_rdev)) &&
- (ti->nor_minor != MINOR (inode->i_rdev)))
- ti = (tape_info_t *) ti->next;
- if (ti == NULL) {
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:nodev");
- #endif
- return -ENODEV;
- }
- // check for discipline ioctl overloading
- if ((rc = ti->discipline->discipline_ioctl_overload (inode, filp, cmd, arg))
- != -EINVAL) {
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:ioverloa");
- #endif
- return rc;
- }
- switch (cmd) {
- case MTIOCTOP: /* tape op command */
- if (copy_from_user (&op, (char *) arg, sizeof (struct mtop))) {
- return -EFAULT;
- }
- return (tape_mtioctop (filp, op.mt_op, op.mt_count));
- case MTIOCPOS: /* query tape position */
- cqr = ti->discipline->mttell (ti, 0);
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- ti->cqr = cqr;
- ti->wanna_wakeup=0;
- 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);
- pos.mt_blkno = ti->rc;
- ti->cqr = NULL;
- if (ti->kernbuf != NULL) {
- kfree (ti->kernbuf);
- ti->kernbuf = NULL;
- }
- tape_free_request (cqr);
- if (signal_pending (current)) {
- tapestate_set (ti, TS_IDLE);
- return -ERESTARTSYS;
- }
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- tapestate_set (ti, TS_IDLE);
- s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
- if (copy_to_user ((char *) arg, &pos, sizeof (struct mtpos)))
- return -EFAULT;
- return 0;
- case MTIOCGET:
- get.mt_erreg = ti->rc;
- cqr = ti->discipline->mttell (ti, 0);
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- ti->cqr = cqr;
- ti->wanna_wakeup=0;
- 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);
- get.mt_blkno = ti->rc;
- get.mt_fileno = 0;
- get.mt_type = MT_ISUNKNOWN;
- get.mt_resid = ti->devstat.rescnt;
- get.mt_dsreg = ti->devstat.ii.sense.data[3];
- get.mt_gstat = 0;
- if (ti->devstat.ii.sense.data[1] & 0x08)
- get.mt_gstat &= GMT_BOT (1); // BOT
- if (ti->devstat.ii.sense.data[1] & 0x02)
- get.mt_gstat &= GMT_WR_PROT (1); // write protected
- if (ti->devstat.ii.sense.data[1] & 0x40)
- get.mt_gstat &= GMT_ONLINE (1); //drive online
- ti->cqr = NULL;
- if (ti->kernbuf != NULL) {
- kfree (ti->kernbuf);
- ti->kernbuf = NULL;
- }
- tape_free_request (cqr);
- if (signal_pending (current)) {
- tapestate_set (ti, TS_IDLE);
- return -ERESTARTSYS;
- }
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- tapestate_set (ti, TS_IDLE);
- s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
- if (copy_to_user ((char *) arg, &get, sizeof (struct mtget)))
- return -EFAULT;
- return 0;
- default:
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,3,"c:ioct inv");
- #endif
- return -EINVAL;
- }
- }
- /*
- * Tape device open function.
- */
- int
- tape_open (struct inode *inode, struct file *filp)
- {
- tape_info_t *ti;
- kdev_t dev;
- long lockflags;
- inode = filp->f_dentry->d_inode;
- ti = first_tape_info;
- while ((ti != NULL) &&
- (ti->rew_minor != MINOR (inode->i_rdev)) &&
- (ti->nor_minor != MINOR (inode->i_rdev)))
- ti = (tape_info_t *) ti->next;
- if (ti == NULL)
- return -ENODEV;
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:open:");
- debug_int_event (tape_debug_area,6,ti->blk_minor);
- #endif
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- if (tapestate_get (ti) != TS_UNUSED) {
- s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:dbusy");
- #endif
- return -EBUSY;
- }
- tapestate_set (ti, TS_IDLE);
- s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
- dev = MKDEV (tape_major, MINOR (inode->i_rdev)); /* Get the device */
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- if (ti->rew_minor == MINOR (inode->i_rdev))
- ti->rew_filp = filp; /* save for later reference */
- else
- ti->nor_filp = filp;
- filp->private_data = ti; /* save the dev.info for later reference */
- s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
- #ifdef MODULE
- MOD_INC_USE_COUNT;
- #endif /* MODULE */
- return 0;
- }
- /*
- * Tape device release function.
- */
- int
- tape_release (struct inode *inode, struct file *filp)
- {
- long lockflags;
- tape_info_t *ti,*lastti;
- ccw_req_t *cqr = NULL;
- int rc = 0;
- ti = first_tape_info;
- while ((ti != NULL) && (ti->rew_minor != MINOR (inode->i_rdev)) && (ti->nor_minor != MINOR (inode->i_rdev)))
- ti = (tape_info_t *) ti->next;
- if ((ti != NULL) && (tapestate_get (ti) == TS_NOT_OPER)) {
- if (ti==first_tape_info) {
- first_tape_info=ti->next;
- } else {
- lastti=first_tape_info;
- while (lastti->next!=ti) lastti=lastti->next;
- lastti->next=ti->next;
- }
- kfree(ti);
- goto out;
- }
- if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) {
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:notidle!");
- #endif
- rc = -ENXIO; /* error in tape_release */
- goto out;
- }
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:release:");
- debug_int_event (tape_debug_area,6,ti->blk_minor);
- #endif
- if (ti->rew_minor == MINOR (inode->i_rdev)) {
- cqr = ti->discipline->mtrew (ti, 1);
- if (cqr != NULL) {
- #ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"c:rewrelea");
- #endif
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- tapestate_set (ti, TS_REW_RELEASE_INIT);
- 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 (ti->wq,ti->wanna_wakeup);
- ti->cqr = NULL;
- tape_free_request (cqr);
- }
- }
- s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
- tapestate_set (ti, TS_UNUSED);
- s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
- out:
- #ifdef MODULE
- MOD_DEC_USE_COUNT;
- #endif /* MODULE */
- return rc;
- }