Enscript Output

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.