Enscript Output

extractedLnx/linux-2.6.9/drivers/scsi/osst.c_osst_int_ioctl.c

static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned int cmd_in, unsigned long arg)
{
	int            timeout;
	long           ltmp;
	int            i, ioctl_result;
	int            chg_eof = TRUE;
	unsigned char  cmd[MAX_COMMAND_SIZE];
	Scsi_Request * SRpnt = * aSRpnt;
	ST_partstat  * STps;
	int            fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
	int            datalen = 0, direction = SCSI_DATA_NONE;
	char         * name = tape_name(STp);

	if (STp->ready != ST_READY && cmd_in != MTLOAD) {
		if (STp->ready == ST_NO_TAPE)
			return (-ENOMEDIUM);
		else
			return (-EIO);
	}
	timeout = STp->long_timeout;
	STps = &(STp->ps[STp->partition]);
	fileno = STps->drv_file;
	blkno = STps->drv_block;
	at_sm = STps->at_sm;
	frame_seq_numbr = STp->frame_seq_number;
	logical_blk_num = STp->logical_blk_num;

	memset(cmd, 0, MAX_COMMAND_SIZE);
	switch (cmd_in) {
	 case MTFSFM:
		chg_eof = FALSE; /* Changed from the FSF after this */
	 case MTFSF:
		if (STp->raw)
		   return (-EIO);
		if (STp->linux_media)
		   ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
		else
		   ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
		if (fileno >= 0)
		   fileno += arg;
		blkno = 0;
		at_sm &= (arg == 0);
		goto os_bypass;

	 case MTBSF:
		chg_eof = FALSE; /* Changed from the FSF after this */
	 case MTBSFM:
		if (STp->raw)
		   return (-EIO);
		ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
		if (fileno >= 0)
		   fileno -= arg;
		blkno = (-1);  /* We can't know the block number */
		at_sm &= (arg == 0);
		goto os_bypass;

	 case MTFSR:
	 case MTBSR:
#if DEBUG
		if (debugging)
		   printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
				name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
#endif
		if (cmd_in == MTFSR) {
		   logical_blk_num += arg;
		   if (blkno >= 0) blkno += arg;
		}
		else {
		   logical_blk_num -= arg;
		   if (blkno >= 0) blkno -= arg;
		}
		ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
		fileno = STps->drv_file;
		blkno  = STps->drv_block;
		at_sm &= (arg == 0);
		goto os_bypass;

	 case MTFSS:
		cmd[0] = SPACE;
		cmd[1] = 0x04; /* Space Setmarks */   /* FIXME -- OS can't do this? */
		cmd[2] = (arg >> 16);
		cmd[3] = (arg >> 8);
		cmd[4] = arg;
#if DEBUG
		if (debugging)
			printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
		cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
		if (arg != 0) {
			blkno = fileno = (-1);
			at_sm = 1;
		}
		break;
	 case MTBSS:
		cmd[0] = SPACE;
		cmd[1] = 0x04; /* Space Setmarks */   /* FIXME -- OS can't do this? */
		ltmp = (-arg);
		cmd[2] = (ltmp >> 16);
		cmd[3] = (ltmp >> 8);
		cmd[4] = ltmp;
#if DEBUG
		if (debugging) {
			if (cmd[2] & 0x80)
			   ltmp = 0xff000000;
			ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
			printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
						name, (-ltmp));
		 }
#endif
		 if (arg != 0) {
			blkno = fileno = (-1);
			at_sm = 1;
		 }
		 break;
	 case MTWEOF:
		 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
			STp->write_type = OS_WRITE_DATA;
			ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
		 } else
			ioctl_result = 0;
#if DEBUG
		 if (debugging) 
			   printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
#endif
		 for (i=0; i<arg; i++)
			ioctl_result |= osst_write_filemark(STp, &SRpnt);
		 if (fileno >= 0) fileno += arg;
		 if (blkno  >= 0) blkno   = 0;
		 goto os_bypass;

	 case MTWSM:
		 if (STp->write_prot)
			return (-EACCES);
		 if (!STp->raw)
			return 0;
		 cmd[0] = WRITE_FILEMARKS;   /* FIXME -- need OS version */
		 if (cmd_in == MTWSM)
			 cmd[1] = 2;
		 cmd[2] = (arg >> 16);
		 cmd[3] = (arg >> 8);
		 cmd[4] = arg;
		 timeout = STp->timeout;
#if DEBUG
		 if (debugging) 
			   printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
				  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
		 if (fileno >= 0)
			fileno += arg;
		 blkno = 0;
		 at_sm = (cmd_in == MTWSM);
		 break;
	 case MTOFFL:
	 case MTLOAD:
	 case MTUNLOAD:
	 case MTRETEN:
		 cmd[0] = START_STOP;
		 cmd[1] = 1;			/* Don't wait for completion */
		 if (cmd_in == MTLOAD) {
		     if (STp->ready == ST_NO_TAPE)
			 cmd[4] = 4;		/* open tray */
		      else
			 cmd[4] = 1;		/* load */
		 }
		 if (cmd_in == MTRETEN)
			 cmd[4] = 3;		/* retension then mount */
		 if (cmd_in == MTOFFL)
			 cmd[4] = 4;		/* rewind then eject */
		 timeout = STp->timeout;
#if DEBUG
		 if (debugging) {
			 switch (cmd_in) {
				 case MTUNLOAD:
					 printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
					 break;
				 case MTLOAD:
					 printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
					 break;
				 case MTRETEN:
					 printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
					 break;
				 case MTOFFL:
					 printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
					 break;
			 }
		 }
#endif
       fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
		 break;
	 case MTNOP:
#if DEBUG
		 if (debugging)
			 printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
#endif
		 return 0;  /* Should do something ? */
		 break;
	 case MTEOM:
#if DEBUG
		if (debugging)
		   printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
#endif
		if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
			    (osst_get_logical_frame(STp, &SRpnt, -1, 0)               < 0)) {
		   ioctl_result = -EIO;
		   goto os_bypass;
		}
		if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
#if DEBUG
		   printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
#endif
		   ioctl_result = -EIO;
		   goto os_bypass;
		}
		ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
		fileno = STp->filemark_cnt;
		blkno  = at_sm = 0;
		goto os_bypass;

	 case MTERASE:
		if (STp->write_prot)
		   return (-EACCES);
		ioctl_result = osst_reset_header(STp, &SRpnt);
		i = osst_write_eod(STp, &SRpnt);
		if (i < ioctl_result) ioctl_result = i;
		i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
		if (i < ioctl_result) ioctl_result = i;
		fileno = blkno = at_sm = 0 ;
		goto os_bypass;

	 case MTREW:
		cmd[0] = REZERO_UNIT; /* rewind */
		cmd[1] = 1;
#if DEBUG
		if (debugging)
		   printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
#endif
		fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
		break;

	 case MTSETBLK:           /* Set block length */
		 if ((STps->drv_block == 0 )			  &&
		     !STp->dirty				  &&
		     ((STp->buffer)->buffer_bytes == 0)		  &&
		     ((arg & MT_ST_BLKSIZE_MASK) >= 512 )	  && 
		     ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
		     !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))  ) {
			 /*
			  * Only allowed to change the block size if you opened the
			  * device at the beginning of a file before writing anything.
			  * Note, that when reading, changing block_size is futile,
			  * as the size used when writing overrides it.
			  */
			 STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
			 printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
					   name, STp->block_size);
			 return 0;
		 }
	 case MTSETDENSITY:       /* Set tape density */
	 case MTSETDRVBUFFER:     /* Set drive buffering */
	 case SET_DENS_AND_BLK:   /* Set density and block size */
		 chg_eof = FALSE;
		 if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
			 return (-EIO);       /* Not allowed if data in buffer */
		 if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
		     (arg & MT_ST_BLKSIZE_MASK) != 0                    &&
		     (arg & MT_ST_BLKSIZE_MASK) != STp->block_size       ) {
			 printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
						name, (int)(arg & MT_ST_BLKSIZE_MASK),
						(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
			 return (-EINVAL);
		 }
		 return 0;  /* FIXME silently ignore if block size didn't change */

	 default:
		return (-ENOSYS);
	}

	SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, TRUE);

	ioctl_result = (STp->buffer)->syscall_result;

	if (!SRpnt) {
#if DEBUG
		printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
#endif
		return ioctl_result;
	}

	if (!ioctl_result) {  /* SCSI command successful */
		STp->frame_seq_number = frame_seq_numbr;
		STp->logical_blk_num  = logical_blk_num;
	}

os_bypass:
#if DEBUG
	if (debugging)
		printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
#endif

	if (!ioctl_result) {				/* success */

		if (cmd_in == MTFSFM) {
			 fileno--;
			 blkno--;
		}
		if (cmd_in == MTBSFM) {
			 fileno++;
			 blkno++;
		}
		STps->drv_block = blkno;
		STps->drv_file = fileno;
		STps->at_sm = at_sm;

		if (cmd_in == MTEOM)
			STps->eof = ST_EOD;
		else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
			ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
			STps->drv_block++;
			STp->logical_blk_num++;
			STp->frame_seq_number++;
			STp->frame_in_buffer = 0;
			STp->buffer->read_pointer = 0;
		}
		else if (cmd_in == MTFSF)
			STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
		else if (chg_eof)
			STps->eof = ST_NOEOF;

		if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
			STp->rew_at_close = 0;
		else if (cmd_in == MTLOAD) {
			for (i=0; i < ST_NBR_PARTITIONS; i++) {
			    STp->ps[i].rw = ST_IDLE;
			    STp->ps[i].last_block_valid = FALSE;/* FIXME - where else is this field maintained? */
			}
			STp->partition = 0;
		}

		if (cmd_in == MTREW) {
			ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); 
			if (ioctl_result > 0)
				ioctl_result = 0;
		}

	} else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
		if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
			STps->drv_file = STps->drv_block = -1;
		else
			STps->drv_file = STps->drv_block = 0;
		STps->eof = ST_NOEOF;
	} else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
		if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
			STps->drv_file = STps->drv_block = -1;
		else {
			STps->drv_file  = STp->filemark_cnt;
			STps->drv_block = 0;
		}
		STps->eof = ST_EOD;
	} else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
		STps->drv_file = STps->drv_block = (-1);
		STps->eof = ST_NOEOF;
		STp->header_ok = 0;
	} else if (cmd_in == MTERASE) {
		STp->header_ok = 0;
	} else if (SRpnt) {  /* SCSI command was not completely successful. */
		if (SRpnt->sr_sense_buffer[2] & 0x40) {
			STps->eof = ST_EOM_OK;
			STps->drv_block = 0;
		}
		if (chg_eof)
			STps->eof = ST_NOEOF;

		if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
			STps->eof = ST_EOD;

		if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
			ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
	}
	*aSRpnt = SRpnt;

	return ioctl_result;
}

Generated by GNU enscript 1.6.4.