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.