if (!capable(CAP_SYS_ADMIN) && (cmd_in == SCSI_IOCTL_START_UNIT || cmd_in == SCSI_IOCTL_STOP_UNIT)) return -EPERM; return scsi_ioctl(STp->device, cmd_in, p); 
retval = scsi_ioctl(STp->device, cmd_in, p); if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */ STp->rew_at_close = 0; STp->ready = ST_NO_TAPE; } return retval; 
static int st_ioctl(struct inode *inode, struct file *file,		    unsigned int cmd_in, unsigned long arg){	int i, cmd_nr, cmd_type, bt;	int retval = 0;	unsigned int blk;	struct scsi_tape *STp = file->private_data;	struct st_modedef *STm;	struct st_partstat *STps;	char *name = tape_name(STp);	void __user *p = (void __user *)arg;	if (down_interruptible(&STp->lock))		return -ERESTARTSYS;        DEB(	if (debugging && !STp->in_use) {		printk(ST_DEB_MSG "%s: Incorrect device.\n", name);		retval = (-EIO);		goto out;	} ) /* end DEB */	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.	 */	retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p, file);	if (!scsi_block_when_processing_errors(STp->device) || retval != -ENODEV)		goto out;	retval = 0;	cmd_type = _IOC_TYPE(cmd_in);	cmd_nr = _IOC_NR(cmd_in);	if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {		struct mtop mtc;		if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {			retval = (-EINVAL);			goto out;		}		i = copy_from_user(&mtc, p, sizeof(struct mtop));		if (i) {			retval = (-EFAULT);			goto out;		}		if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {			printk(KERN_WARNING                               "%s: 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 = flush_buffer(STp, i);			if (i < 0) {				retval = i;				goto out;			}			if (STps->rw == ST_WRITING &&			    (mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||			     mtc.mt_op == MTSEEK ||			     mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)) {				i = st_int_ioctl(STp, MTWEOF, 1);				if (i < 0) {					retval = i;					goto out;				}				if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)					mtc.mt_count++;				STps->rw = ST_IDLE;			     }		} 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 != MTNOP && mtc.mt_op != MTSETBLK &&		    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&		    mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)			STps->rw = ST_IDLE;	/* Prevent automatic WEOF and fsf */		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 = st_set_options(STp, mtc.mt_count);			goto out;		}		if (mtc.mt_op == MTSETPART) {			if (!STp->can_partitions ||			    mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) {				retval = (-EINVAL);				goto out;			}			if (mtc.mt_count >= STp->nbr_partitions &&			    (STp->nbr_partitions = nbr_partitions(STp)) < 0) {				retval = (-EIO);				goto out;			}			if (mtc.mt_count >= STp->nbr_partitions) {				retval = (-EINVAL);				goto out;			}			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 = st_int_ioctl(STp, MTREW, 0)) < 0 ||			    (i = partition_tape(STp, 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 = 0;			}			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) {			i = set_location(STp, mtc.mt_count, STp->new_partition, 0);			if (!STp->can_partitions)				STp->ps[0].rw = ST_IDLE;			retval = i;			goto out;		}		if (mtc.mt_op == MTUNLOAD || mtc.mt_op == MTOFFL) {			retval = do_load_unload(STp, file, 0);			goto out;		}		if (mtc.mt_op == MTLOAD) {			retval = do_load_unload(STp, file, max(1, mtc.mt_count));			goto out;		}		if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {			retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));			goto out;		}		if (STp->can_partitions && STp->ready == ST_READY &&		    (i = switch_partition(STp)) < 0) {			retval = i;			goto out;		}		if (mtc.mt_op == MTCOMPRESSION)			retval = st_compression(STp, (mtc.mt_count & 1));		else			retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);		goto out;	}	if (!STm->defined) {		retval = (-ENXIO);		goto out;	}	if ((i = flush_buffer(STp, 0)) < 0) {		retval = i;		goto out;	}	if (STp->can_partitions &&	    (i = switch_partition(STp)) < 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 = STp->tape_type;		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_erreg = (STp->recover_reg << MT_ST_SOFTERR_SHIFT);		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);		if (STp->cleaning_req)			mt_status.mt_gstat |= GMT_CLN(0xffffffff);		i = copy_to_user(p, &mt_status, sizeof(struct mtget));		if (i) {			retval = (-EFAULT);			goto out;		}		STp->recover_reg = 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 ((i = get_location(STp, &blk, &bt, 0)) < 0) {			retval = i;			goto out;		}		mt_pos.mt_blkno = blk;		i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));		if (i)			retval = (-EFAULT);		goto out;	}	up(&STp->lock);	switch (cmd_in) {		case SCSI_IOCTL_GET_IDLUN:		case SCSI_IOCTL_GET_BUS_NUMBER:			break;		default:			if (!capable(CAP_SYS_ADMIN))				i = -EPERM;			else				i = scsi_cmd_ioctl(file, STp->disk, cmd_in, p);			if (i != -ENOTTY)				return i;			break;	}	if (!capable(CAP_SYS_ADMIN) &&	    (cmd_in == SCSI_IOCTL_START_UNIT || cmd_in == SCSI_IOCTL_STOP_UNIT))		return -EPERM;	return scsi_ioctl(STp->device, cmd_in, p); out:	up(&STp->lock);	return retval;}
4520	/local/tlutelli/issta_data/temp/c/2005_temp/2005/4520/16c4b3e2071ad73e5cd2aa82961eed0414df6a7d/st.c/clean/drivers/scsi/st.c