extractedLnx/linux-2.6.9/drivers/scsi/osst.c_osst_ioctl.c
static int osst_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg)
{
int i, cmd_nr, cmd_type, retval = 0;
unsigned int blk;
ST_mode * STm;
ST_partstat * STps;
Scsi_Request * SRpnt = NULL;
OS_Scsi_Tape * STp = file->private_data;
char * name = tape_name(STp);
void __user *p = (void __user *)arg;
if (down_interruptible(&STp->lock))
return -ERESTARTSYS;
#if DEBUG
if (debugging && !STp->in_use) {
printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
retval = (-EIO);
goto out;
}
#endif
STm = &(STp->modes[STp->current_mode]);
STps = &(STp->ps[STp->partition]);
/*
* If we are in the middle of error recovery, don't let anyone
* else try and use this device. Also, if error recovery fails, it
* may try and take the device offline, in which case all further
* access to the device is prohibited.
*/
if( !scsi_block_when_processing_errors(STp->device) ) {
retval = (-ENXIO);
goto out;
}
cmd_type = _IOC_TYPE(cmd_in);
cmd_nr = _IOC_NR(cmd_in);
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
cmd_type, cmd_nr, STp->raw?"raw":"normal");
#endif
if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
struct mtop mtc;
int auto_weof = 0;
if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
retval = (-EINVAL);
goto out;
}
i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
if (i) {
retval = (-EFAULT);
goto out;
}
if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
retval = (-EPERM);
goto out;
}
if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
retval = (-ENXIO);
goto out;
}
if (!STp->pos_unknown) {
if (STps->eof == ST_FM_HIT) {
if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
mtc.mt_count -= 1;
if (STps->drv_file >= 0)
STps->drv_file += 1;
}
else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
mtc.mt_count += 1;
if (STps->drv_file >= 0)
STps->drv_file += 1;
}
}
if (mtc.mt_op == MTSEEK) {
/* Old position must be restored if partition will be changed */
i = !STp->can_partitions || (STp->new_partition != STp->partition);
}
else {
i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
mtc.mt_op == MTCOMPRESSION;
}
i = osst_flush_buffer(STp, &SRpnt, i);
if (i < 0) {
retval = i;
goto out;
}
}
else {
/*
* If there was a bus reset, block further access
* to this device. If the user wants to rewind the tape,
* then reset the flag and allow access again.
*/
if(mtc.mt_op != MTREW &&
mtc.mt_op != MTOFFL &&
mtc.mt_op != MTRETEN &&
mtc.mt_op != MTERASE &&
mtc.mt_op != MTSEEK &&
mtc.mt_op != MTEOM) {
retval = (-EIO);
goto out;
}
reset_state(STp);
/* remove this when the midlevel properly clears was_reset */
STp->device->was_reset = 0;
}
if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART &&
mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) {
/*
* The user tells us to move to another position on the tape.
* If we were appending to the tape content, that would leave
* the tape without proper end, in that case write EOD and
* update the header to reflect its position.
*/
#if DEBUG
printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
STp->logical_blk_num, STps->drv_file, STps->drv_block );
#endif
if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
!(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
i = osst_write_trailer(STp, &SRpnt,
!(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
#if DEBUG
printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
#endif
if (i < 0) {
retval = i;
goto out;
}
}
STps->rw = ST_IDLE;
}
if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
do_door_lock(STp, 0); /* Ignore result! */
if (mtc.mt_op == MTSETDRVBUFFER &&
(mtc.mt_count & MT_ST_OPTIONS) != 0) {
retval = osst_set_options(STp, mtc.mt_count);
goto out;
}
if (mtc.mt_op == MTSETPART) {
if (mtc.mt_count >= STp->nbr_partitions)
retval = -EINVAL;
else {
STp->new_partition = mtc.mt_count;
retval = 0;
}
goto out;
}
if (mtc.mt_op == MTMKPART) {
if (!STp->can_partitions) {
retval = (-EINVAL);
goto out;
}
if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
(i = partition_tape(inode, mtc.mt_count)) < 0*/) {
retval = i;
goto out;
}
for (i=0; i < ST_NBR_PARTITIONS; i++) {
STp->ps[i].rw = ST_IDLE;
STp->ps[i].at_sm = 0;
STp->ps[i].last_block_valid = FALSE;
}
STp->partition = STp->new_partition = 0;
STp->nbr_partitions = 1; /* Bad guess ?-) */
STps->drv_block = STps->drv_file = 0;
retval = 0;
goto out;
}
if (mtc.mt_op == MTSEEK) {
if (STp->raw)
i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
else
i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
if (!STp->can_partitions)
STp->ps[0].rw = ST_IDLE;
retval = i;
goto out;
}
if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
goto out;
}
if (auto_weof)
cross_eof(STp, &SRpnt, FALSE);
if (mtc.mt_op == MTCOMPRESSION)
retval = -EINVAL; /* OnStream drives don't have compression hardware */
else
/* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
* MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
goto out;
}
if (!STm->defined) {
retval = (-ENXIO);
goto out;
}
if ((i = osst_flush_buffer(STp, &SRpnt, FALSE)) < 0) {
retval = i;
goto out;
}
if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
struct mtget mt_status;
if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
retval = (-EINVAL);
goto out;
}
mt_status.mt_type = MT_ISONSTREAM_SC;
mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
mt_status.mt_dsreg =
((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
mt_status.mt_blkno = STps->drv_block;
mt_status.mt_fileno = STps->drv_file;
if (STp->block_size != 0) {
if (STps->rw == ST_WRITING)
mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
else if (STps->rw == ST_READING)
mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
STp->block_size - 1) / STp->block_size;
}
mt_status.mt_gstat = 0;
if (STp->drv_write_prot)
mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
if (mt_status.mt_blkno == 0) {
if (mt_status.mt_fileno == 0)
mt_status.mt_gstat |= GMT_BOT(0xffffffff);
else
mt_status.mt_gstat |= GMT_EOF(0xffffffff);
}
mt_status.mt_resid = STp->partition;
if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
mt_status.mt_gstat |= GMT_EOT(0xffffffff);
else if (STps->eof >= ST_EOM_OK)
mt_status.mt_gstat |= GMT_EOD(0xffffffff);
if (STp->density == 1)
mt_status.mt_gstat |= GMT_D_800(0xffffffff);
else if (STp->density == 2)
mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
else if (STp->density == 3)
mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
if (STp->ready == ST_READY)
mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
if (STp->ready == ST_NO_TAPE)
mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
if (STps->at_sm)
mt_status.mt_gstat |= GMT_SM(0xffffffff);
if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
STp->drv_buffer != 0)
mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
i = copy_to_user(p, &mt_status, sizeof(struct mtget));
if (i) {
retval = (-EFAULT);
goto out;
}
STp->recover_erreg = 0; /* Clear after read */
retval = 0;
goto out;
} /* End of MTIOCGET */
if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
struct mtpos mt_pos;
if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
retval = (-EINVAL);
goto out;
}
if (STp->raw)
blk = osst_get_frame_position(STp, &SRpnt);
else
blk = osst_get_sector(STp, &SRpnt);
if (blk < 0) {
retval = blk;
goto out;
}
mt_pos.mt_blkno = blk;
i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
if (i)
retval = -EFAULT;
goto out;
}
if (SRpnt) scsi_release_request(SRpnt);
up(&STp->lock);
return scsi_ioctl(STp->device, cmd_in, p);
out:
if (SRpnt) scsi_release_request(SRpnt);
up(&STp->lock);
return retval;
}
Generated by GNU enscript 1.6.4.